home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / cybersound / cdplayer / source / cdplayer.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  33KB  |  1,382 lines

  1.  
  2. /********************************************
  3.  * CD Audio Player using 14bit sound driver *
  4.  *   for Toshiba 4101 CDRom and compatible  *
  5.  *      (c) 1995 by Christian Buchner       *
  6.  ********************************************
  7.  *
  8.  * CDPlayer.c
  9.  */
  10.  
  11. /* Note: TAB SIZE = 4 */
  12.  
  13.  
  14. /* Includes */
  15.  
  16. #include <proto/dos.h>
  17. #include <proto/exec.h>
  18. #include <proto/intuition.h>
  19. #include <clib/alib_stdio_protos.h>
  20. #include <libraries/dos.h>
  21. #include <intuition/intuition.h>
  22. #include <exec/io.h>
  23. #include <exec/memory.h>
  24. #include <devices/scsidisk.h>
  25. #include <string.h>
  26. #include <stdarg.h>
  27.  
  28. #include "//14bit.driver/Source/Driver_protos.h"
  29. #include "//14bit.driver/Source/Driver_pragmas.h"
  30. #include "//14bit.driver/Source/Driver.h"
  31.  
  32.  
  33. /* Prototypes */
  34.  
  35. #include "CDPlayer_Protos.h"
  36.  
  37.  
  38. /* Version String */
  39.  
  40. char *VersionString = VERSION_STRING;
  41.  
  42.  
  43. /* CDDA constants */
  44.  
  45. #define CDDA_BLOCKSIZE 2352        /* size of one CDDA block */
  46. #define ONE_SECOND 75            /* blocks per second (75) */
  47.  
  48.  
  49. /* Values defining sound buffers and sound output */
  50.  
  51. ULONG BUFBLOCKS=20;                /* Buffer size in blocks (allocated 3 times) */
  52. ULONG FREQUENCY=44100;            /* Desired replay frequency */
  53. ULONG QUALITY=1;                /* 1 for maximum quality (44khz) */
  54.  
  55.  
  56. /* Library bases */
  57.  
  58. struct DosLibrary *DOSBase;
  59. struct IntuitionBase *IntuitionBase;
  60. struct Library *DriverBase;
  61.  
  62.  
  63. /* Synchronous SCSI IO */
  64.  
  65. LONG SyncSigBit= -1;
  66. struct MsgPort SyncReplyPort;
  67. struct IOStdReq SyncSCSI_IO;
  68. struct SCSICmd SyncSCSICmd;
  69.  
  70.  
  71. /* Asynchronous SCSI IO */
  72.  
  73. struct MsgPort AsyncReplyPort;        /* note: only ONE port necessary */
  74. struct IOStdReq AsyncSCSI_IO[3];
  75. struct SCSICmd AsyncSCSICmd[3];
  76.  
  77.  
  78. /* Definition of the buffer states */
  79.  
  80. enum States
  81. {
  82.     BUF_EMPTY,
  83.     BUF_LOADING,
  84.     BUF_FILLED,
  85.     BUF_PLAYING,
  86. };
  87.  
  88.  
  89. /* Status variables used for replay */
  90.  
  91. ULONG Read_CB;            /* Read current buffer */
  92. ULONG ReadReply_CB;        /* Read reply current buffer */
  93. ULONG Play_CB;            /* Play current buffer */
  94. ULONG PlayReply_CB;        /* Play reply cuttent buffer */
  95.  
  96. ULONG LoadLBA;            /* the block currently being loaded */
  97. ULONG TargetLBA;        /* the end block for current (continuous) replay */
  98. ULONG PlayLBA;            /* the LBA that was just played */
  99.  
  100. UWORD Status[3];        /* the buffer states */
  101. UWORD *Buffer[3];        /* pointers to the buffers themselves */
  102. ULONG BytesRead[3];        /* buffer contents, only valid for BUF_FILLED */
  103. ULONG BufEndLBA[3];        /* The end LBA of the buffers plus one */
  104. UWORD BufEndIndex[3];    /* The EndIndex value when the buffers were loaded */
  105.  
  106. UWORD Num_Playing;        /* number of pending play requests */
  107. UWORD Num_Reading;        /* number of pending read requests */
  108. BOOL Active;            /* allow reading and playing of data */
  109. BOOL Playing;            /* allow sound output (used for synchronization) */
  110.  
  111.  
  112. /* Priority management (PromotePri flag) */
  113.  
  114. BOOL HighPri;            /* scsi driver's priority is to be "promoted" */
  115. BOOL HighPriSet;        /* value in OldPri is valid */
  116. UBYTE OldPri;            /* old priority of the scsi driver */
  117. struct Task *SCSITask;    /* the task that OldPri belongs to */
  118.  
  119. BOOL AltPriSet;            /* This is for A2091 specifically */
  120. UBYTE OldAltPri;
  121. struct Task *AltSCSITask;
  122.  
  123.  
  124. /* Variables for Program management */
  125.  
  126. UWORD MaxIndex;            /* number of entries in the program (=maximum index)*/
  127. UBYTE Program[129];        /* the program itself, element [0] is not used! */
  128. UWORD CurrentIndex;        /* the current (playing) index */
  129. UWORD EndIndex;            /* the last index of continuous replay */
  130. void (*CallBack)(void);    /* callback function when program end reached */
  131.  
  132.  
  133. /* SCSI command and mode structures */
  134.  
  135. struct Read12
  136. {
  137.     UBYTE cmd;            /* READ(12) SCSI command 0xA8 */
  138.     UBYTE pad_a;        /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  139.     ULONG lba;            /* logical block address MSB, , ,LSB */
  140.     ULONG lbn;            /* number of blocks to transfer MSB, , ,LSB */
  141.     UBYTE subcode;        /* special sub code selector (only for SONY!)
  142.                          * 0: normal 2352
  143.                          * 1: 2368
  144.                          * 2: 2448
  145.                          * 3: 96 bytes */
  146.     UBYTE cntrl;        /* Control */
  147. };
  148.  
  149. struct ModeSense
  150. {
  151.     UBYTE cmd;
  152.     UBYTE pad_a;
  153.     UBYTE page;
  154.     UBYTE reserved;
  155.     UBYTE alloclen;
  156.     UBYTE cntrl;
  157. };
  158.  
  159. struct ModeSelect
  160. {
  161.     UBYTE cmd;
  162.     UBYTE pageformat;
  163.     UBYTE reserved_a;
  164.     UBYTE reserved_b;
  165.     UBYTE plistlen;
  166.     UBYTE cntrl;
  167. };
  168.  
  169. struct ModeData
  170. {
  171. /* 4 Byte Mode Parameter Header (Table 7-61) */
  172.     UBYTE mode_data_length;
  173.     UBYTE medium_type;
  174.     UBYTE device_specific_parameter;
  175.     UBYTE block_descriptor_length;
  176. /* 8 Byte Mode Parameter Block Descriptor (Table 7-63) */
  177.     UBYTE density;
  178.     UBYTE num_blocks_H;
  179.     UBYTE num_blocks_M;
  180.     UBYTE num_blocks_L;
  181.     ULONG block_length;
  182. };
  183.  
  184. struct Inquiry
  185. {
  186.     UBYTE cmd;
  187.     UBYTE pad_a;
  188.     UBYTE page;
  189.     UBYTE reserved;
  190.     UBYTE alloclen;
  191.     UBYTE cntrl;
  192. };
  193.  
  194. struct InquiryData
  195. {
  196.     UBYTE pdevtype;
  197.     UBYTE rmb_devtypmod;
  198.     UBYTE versions;
  199.     UBYTE rdformat;
  200.     UBYTE addlength;
  201.     UBYTE reserved_a;
  202.     UBYTE reserved_b;
  203.     UBYTE lotsofbits;
  204.     UBYTE vendor[8];
  205.     UBYTE prod_id[16];
  206.     UBYTE revision[4];
  207.     UBYTE specific[20];
  208.     UBYTE reserved[40];
  209. };
  210.  
  211. struct ReadTOC
  212. {
  213.     UBYTE cmd;
  214.     UBYTE misc;
  215.     ULONG reserved;
  216.     UBYTE starttrack;
  217.     UBYTE alloclenHI;
  218.     UBYTE alloclenLO;
  219.     UBYTE control;
  220. };
  221.  
  222. struct TrackDesc
  223. {
  224.     UBYTE reserved;
  225.     UBYTE adrctrl;
  226.     UBYTE trackno;
  227.     UBYTE reserved2;
  228.     ULONG lba;
  229. };
  230.  
  231. struct TOCData
  232. {
  233.     UWORD length;
  234.     UBYTE lowtrack;
  235.     UBYTE hightrack;
  236.     struct TrackDesc desc[100];
  237. };
  238.  
  239. struct SenseData
  240. {
  241.     UBYTE errcode;
  242.     UBYTE segnum;
  243.     UBYTE sensekey;
  244.     UBYTE information[4];
  245.     UBYTE addlength;
  246.     UBYTE specificinfo[4];
  247.     UWORD additionalsense;
  248.     UBYTE unitcode;
  249.     UBYTE sensekeyspec[3];
  250.     UBYTE space[20];
  251. };
  252.  
  253.  
  254. /* SCSI command and data bytes (somewhat pre-initialized) */
  255.  
  256. struct SenseData SyncSenseData;
  257. struct SenseData AsyncSenseData[3];
  258.  
  259. struct Read12 Read12[3]=
  260.     
  261.     { 0xA8, 0x00, 0, 0, 0, 0,
  262.       0xA8, 0x00, 0, 0, 0, 0,
  263.       0xA8, 0x00, 0, 0, 0, 0 };
  264.  
  265. struct InquiryData InquiryData;
  266. struct Inquiry Inquiry={0x12, 0x00, 0, 0, sizeof(InquiryData), 0};
  267.  
  268. struct ModeData OldModePage;
  269. struct ModeData NewModePage={0,0,0,8, 0x82,0,0,0,CDDA_BLOCKSIZE};
  270.  
  271. struct ModeSense  ModeSense ={0x1A,    0, 1, 0, sizeof(OldModePage), 0};
  272. struct ModeSelect ModeSelect={0x15, 0x10, 0, 0, sizeof(NewModePage), 0};
  273.  
  274. struct TOCData TOCData;
  275. struct ReadTOC ReadTOC={0x43, 0, 0, 0, sizeof(TOCData)>>8, sizeof(TOCData)&0xff, 0};
  276.  
  277.  
  278. /*******************************************************************************/
  279.  
  280. /* Generate a program from a ReadArgs style tracklist */
  281.  
  282. UWORD CD_SetProgram(ULONG **tracklist, void (*callback)(void))
  283. {
  284.     ULONG Track;
  285.     
  286.     /* Initialize callback hook (called when program is finished) */
  287.     CallBack=callback;
  288.     
  289.     /* Generate a full program, if tracklist or *tracklist is NULL */
  290.     if (tracklist==NULL || *tracklist==NULL)
  291.     {
  292.         /* Loop all tracks */
  293.         for (MaxIndex=0,Track=TOCData.lowtrack;Track<=TOCData.hightrack;Track++)
  294.         {
  295.             if (CheckAudio(Track))
  296.             {
  297.                 MaxIndex++;
  298.                 Program[MaxIndex]=Track;
  299.             }
  300.         }
  301.     }
  302.     else
  303.     {
  304.         /* Generate a program from all playable tracks in the tracklist */
  305.         for (MaxIndex=0;*tracklist;tracklist++)
  306.         {
  307.             if (CheckAudio(**tracklist))
  308.             {
  309.                 MaxIndex++;
  310.                 Program[MaxIndex]= **tracklist;
  311.             }
  312.         }
  313.     }
  314.     
  315.     /* Restart track list */
  316.     CD_ToIndex(1);
  317.     
  318.     return(MaxIndex);
  319. }
  320.  
  321.  
  322. /*******************************************************************************/
  323.  
  324. /* Position at specified index in program */
  325.  
  326. UWORD CD_ToIndex(UWORD Index)
  327. {
  328.     UWORD Result=0;
  329.     
  330.     if (Index>=1 && Index<=MaxIndex)
  331.     {
  332.         Result=CurrentIndex=Index;
  333.         
  334.         /* Set start LBAs for replay */
  335.         LoadLBA=TargetLBA=PlayLBA=TOCData.desc[Program[Index]-TOCData.lowtrack].lba;
  336.         
  337.         /* Find out how many tracks can be played continuously */
  338.         while(Index<=MaxIndex && TargetLBA==TOCData.desc[Program[Index]-TOCData.lowtrack].lba)
  339.         {
  340.             EndIndex=Index;
  341.             TargetLBA=TOCData.desc[Program[Index]-TOCData.lowtrack+1].lba;
  342.             Index++;
  343.         }
  344.     }
  345.     
  346.     return(Result);
  347. }
  348.  
  349.  
  350. /*******************************************************************************/
  351.  
  352. /* Get Index of currently positioned title */
  353.  
  354. UWORD CD_CurrentIndex(void)
  355. {
  356.     return(CurrentIndex);
  357. }
  358.  
  359.  
  360. /*******************************************************************************/
  361.  
  362. /* Get currently positioned title */
  363.  
  364. UWORD CD_CurrentTrack(void)
  365. {
  366.     return(Program[CurrentIndex]);
  367. }
  368.  
  369.  
  370. /*******************************************************************************/
  371.  
  372. /* Get current position in track (returned in LBAs) */
  373.  
  374. ULONG CD_CurrentPosition(void)
  375. {
  376.     return(PlayLBA-TOCData.desc[Program[CurrentIndex]-TOCData.lowtrack].lba);
  377. }
  378.  
  379.  
  380. /*******************************************************************************/
  381.  
  382. /* Skip to next index */
  383.  
  384. UWORD CD_NextIndex(void)
  385. {
  386.     BOOL Restart;
  387.     UWORD ResIndex=0;
  388.     
  389.     if (CurrentIndex<MaxIndex)
  390.     {
  391.         Restart=CD_Abort();
  392.         
  393.         ResIndex=CD_ToIndex(CurrentIndex+1);
  394.         
  395.         if (Restart) CD_Start();
  396.     }
  397.     return(ResIndex);
  398. }
  399.  
  400.  
  401. /*******************************************************************************/
  402.  
  403. /* Skip to previous index */
  404.  
  405. UWORD CD_PrevIndex(void)
  406. {
  407.     BOOL Restart;
  408.     UWORD ResIndex=0;
  409.     
  410.     if (CurrentIndex>1)
  411.     {
  412.         Restart=CD_Abort();
  413.         
  414.         ResIndex=CD_ToIndex(CurrentIndex-1);
  415.         
  416.         if (Restart) CD_Start();
  417.     }
  418.     return(ResIndex);
  419. }
  420.  
  421.  
  422. /*******************************************************************************/
  423.  
  424. void CD_Skip(WORD seconds)
  425. {
  426.     BOOL Restart;
  427.     LONG LBA;
  428.     
  429.     Restart=CD_Abort();
  430.     
  431.     LBA=LoadLBA+(LONG)ONE_SECOND*seconds;
  432.     if (LBA < 0) LBA=0;
  433.     if (LBA > TargetLBA) LBA=TargetLBA;
  434.     LoadLBA=LBA;
  435.     
  436.     if (Restart) CD_Start();
  437. }
  438.  
  439.  
  440. /*******************************************************************************/
  441.  
  442. /* Initialize buffers */
  443.  
  444. void CD_Init(void)
  445. {
  446.     /* Init flags */
  447.     Active=FALSE;
  448.     Playing=FALSE;
  449.     
  450.     /* Reset buffer status */
  451.     Status[0]=Status[1]=Status[2]=BUF_EMPTY;
  452.     
  453.     /* Reset current buffer counters */
  454.     Read_CB=0;
  455.     ReadReply_CB=0;
  456.     Play_CB=0;
  457.     PlayReply_CB=0;
  458. }
  459.  
  460.  
  461. /*******************************************************************************/
  462.  
  463. /* Start playing */
  464.  
  465. void CD_Start(void)
  466. {
  467.     Active=TRUE;
  468.     
  469.     /* Start playing */
  470.     ReadBuffer();
  471. }
  472.  
  473.  
  474. /*******************************************************************************/
  475.  
  476. /* Abort playing and wait until replay has finished */
  477. /* returns TRUE if CD was actually playing */
  478.  
  479. BOOL CD_Abort(void)
  480. {
  481.     UWORD i;
  482.     BOOL OldActive=Active;
  483.     
  484.     /* Now we have to stop playing */
  485.     Active=FALSE;
  486.     Playing=FALSE;
  487.     
  488.     /* Abort sound replay */
  489.     FlushStream();
  490.     
  491.     /* Abort reading */
  492.     for (i=0;i<2;i++)
  493.     {
  494.         if (Status[i]==BUF_LOADING)
  495.         {
  496.             AbortIO((struct IORequest*)&AsyncSCSI_IO[i]);
  497.         }
  498.     }
  499.     
  500.     /* Wait until buffer status is idle */
  501.     while(   Num_Reading!=0    ||     Num_Playing!=0     ||
  502.          (Status[0]!=BUF_EMPTY && Status[0]!=BUF_FILLED) ||
  503.          (Status[1]!=BUF_EMPTY && Status[1]!=BUF_FILLED) ||
  504.          (Status[2]!=BUF_EMPTY && Status[2]!=BUF_FILLED) )
  505.     {
  506.         Delay(10);
  507.     }
  508.     
  509.     /* Reinitialize buffers */
  510.     CD_Init();
  511.     
  512.     return(OldActive);
  513. }
  514.  
  515.  
  516. /*******************************************************************************/
  517.  
  518. /* Pause replay */
  519.  
  520. void CD_Pause(void)
  521. {
  522.     PauseStream();
  523. }
  524.  
  525.  
  526. /*******************************************************************************/
  527.  
  528. /* Resume replay */
  529.  
  530. void CD_Resume(void)
  531. {
  532.     ResumeStream();
  533. }
  534.  
  535.  
  536. /*******************************************************************************/
  537.  
  538. /* Change frequency */
  539.  
  540. void CD_Frequency(ULONG frequency)
  541. {
  542.     FREQUENCY=frequency;
  543. }
  544.  
  545.  
  546. /*******************************************************************************/
  547.  
  548. /* Change quality */
  549.  
  550. void CD_Quality(ULONG quality)
  551. {
  552.     QUALITY=quality;
  553. }
  554.  
  555.  
  556. /*******************************************************************************/
  557.  
  558. /* Check if a track can be played */
  559.  
  560. BOOL CheckAudio(ULONG Track)
  561. {
  562.     if (Track>=TOCData.lowtrack && Track<=TOCData.hightrack)
  563.     {
  564.         if ((TOCData.desc[Track-TOCData.lowtrack].adrctrl & 0xf)==0)
  565.         {
  566.             return(TRUE);
  567.         }
  568.     }
  569.     return(FALSE);
  570. }
  571.  
  572.  
  573. /*******************************************************************************/
  574.  
  575. /* Open and initialize CDRom */
  576.  
  577. BOOL OpenSCSI(UBYTE *Device, ULONG Unit, BOOL PromotePri)
  578. {
  579.     BOOL Success=FALSE;
  580.     UWORD i;
  581.     
  582.     /* Store HighPri flag */
  583.     HighPri=PromotePri;
  584.     
  585.     /* Init synchronous SCSI IO */
  586.     
  587.     SyncReplyPort.mp_Node.ln_Type=NT_MSGPORT;
  588.     SyncReplyPort.mp_Flags=PA_SIGNAL;
  589.     SyncReplyPort.mp_SigTask=FindTask(NULL);
  590.     NewList(&SyncReplyPort.mp_MsgList);
  591.     
  592.     if ((SyncSigBit=SyncReplyPort.mp_SigBit=AllocSignal(-1))!=-1)
  593.     {
  594.         SyncSCSI_IO.io_Message.mn_Node.ln_Type=NT_MESSAGE;
  595.         SyncSCSI_IO.io_Message.mn_Length=sizeof(struct IOStdReq);
  596.         
  597.         SyncSCSI_IO.io_Message.mn_ReplyPort= &SyncReplyPort;
  598.         SyncSCSI_IO.io_Data= &SyncSCSICmd;
  599.         
  600.         SyncSCSICmd.scsi_SenseData=(UBYTE*)&SyncSenseData;
  601.         SyncSCSICmd.scsi_SenseLength=sizeof(SyncSenseData);
  602.         
  603.         /* Init asynchronous SCSI IO */
  604.         
  605.         AsyncReplyPort.mp_Node.ln_Type=NT_MSGPORT;
  606.         AsyncReplyPort.mp_Flags=PF_ACTION;
  607.         AsyncReplyPort.mp_SigTask=(APTR)&SCSIReply;
  608.         NewList(&AsyncReplyPort.mp_MsgList);
  609.         
  610.         for (i=0;i<3;i++)
  611.         {
  612.             AsyncSCSI_IO[i].io_Message.mn_Node.ln_Type=NT_MESSAGE;
  613.             AsyncSCSI_IO[i].io_Message.mn_Length=sizeof(struct IOStdReq);
  614.             
  615.             AsyncSCSI_IO[i].io_Message.mn_ReplyPort= &AsyncReplyPort;
  616.             AsyncSCSI_IO[i].io_Data= &AsyncSCSICmd[i];
  617.             
  618.             AsyncSCSICmd[i].scsi_SenseData=(UBYTE*)&AsyncSenseData[i];
  619.             AsyncSCSICmd[i].scsi_SenseLength=sizeof(AsyncSenseData[i]);
  620.         }
  621.         
  622.         if (OpenDevice(Device,Unit,(struct IORequest*)&SyncSCSI_IO,0))
  623.         {
  624.             Message("Cannot open '%s' unit %ld.",Device,Unit);
  625.         }
  626.         else
  627.         {
  628.             for (i=0;i<3;i++)
  629.             {
  630.                 AsyncSCSI_IO[i].io_Device=SyncSCSI_IO.io_Device;
  631.                 AsyncSCSI_IO[i].io_Unit=SyncSCSI_IO.io_Unit;
  632.             }
  633.             if (DoSCSI(&SyncSCSI_IO, &Inquiry, sizeof(Inquiry), &InquiryData, sizeof(InquiryData), SCSIF_READ, FALSE, "reading inquiry data"))
  634.             {
  635.                 if (InquiryData.pdevtype != 5)
  636.                 {
  637.                     Message("'%s' unit %ld is not a CDRom!",Device,Unit);
  638.                 }
  639.                 else
  640.                 {
  641.                     /* Read Table of Contents */
  642.                     if (!(DoSCSI(&SyncSCSI_IO, &ReadTOC, sizeof(ReadTOC), &TOCData, sizeof(TOCData), SCSIF_READ, FALSE, "reading table of contents")))
  643.                     {
  644.                         Message("Cannot read Table of Contents!");
  645.                     }
  646.                     else
  647.                     {
  648.                         /* Prepare CDRom for CDDA data transfer */
  649.                         DoSCSI(&SyncSCSI_IO, &ModeSense, sizeof(ModeSense), &OldModePage, sizeof(OldModePage), SCSIF_READ, FALSE, "reading mode page");
  650.                         DoSCSI(&SyncSCSI_IO, &ModeSelect, sizeof(ModeSelect), &NewModePage, sizeof(NewModePage), SCSIF_WRITE, FALSE, "selecting CD-DA data format");
  651.                         
  652.                         /* Initialize buffers */
  653.                         CD_Init();
  654.                         
  655.                         Success=TRUE;
  656.                     }
  657.                 }
  658.             }
  659.         }
  660.     }
  661.     if (!Success) CloseSCSI();
  662.     
  663.     return(Success);
  664. }
  665.  
  666.  
  667. /*******************************************************************************/
  668.  
  669. /* Reset and close CDRom */
  670.  
  671. void CloseSCSI(void)
  672. {
  673.     /* Reset priority of the SCSI driver task(s) */
  674.     if (HighPriSet && SCSITask)
  675.     {
  676.         SCSITask->tc_Node.ln_Pri=OldPri;
  677.         HighPriSet=FALSE;
  678.         
  679.         if (AltPriSet && AltSCSITask)
  680.         {
  681.             AltSCSITask->tc_Node.ln_Pri=OldAltPri;
  682.             AltPriSet=FALSE;
  683.         }
  684.     }
  685.     
  686.     if (SyncSCSI_IO.io_Device)
  687.     {
  688.         /* Reset CDRom transfer mode */
  689.         if (OldModePage.mode_data_length>0)
  690.         {
  691.             OldModePage.mode_data_length=0;
  692.             DoSCSI(&SyncSCSI_IO, &ModeSelect, sizeof(ModeSelect), &OldModePage, sizeof(OldModePage), SCSIF_WRITE, FALSE, "resetting data format");
  693.         }
  694.         CloseDevice((struct IORequest*)&SyncSCSI_IO);
  695.         SyncSCSI_IO.io_Device=NULL;
  696.     }
  697.     if (SyncSigBit!=-1)
  698.     {
  699.         FreeSignal(SyncSigBit);
  700.         SyncSigBit= -1;
  701.     }
  702. }
  703.  
  704.  
  705. /*******************************************************************************/
  706.  
  707. /* Open and Init sound driver/buffers */
  708.  
  709. BOOL InitDriver(UBYTE *Driver, ULONG Buffers)
  710. {
  711.     BOOL Success=FALSE;
  712.     UBYTE DriverPath[80];
  713.     UWORD i;
  714.     
  715.     strcpy(DriverPath, "DEVS:SoundDrivers/");
  716.     strcat(DriverPath, Driver);
  717.     
  718.     if (!(DriverBase=OpenLibrary(DriverPath,0)))
  719.     {
  720.         Message("Cannot open sound driver '%s'.",DriverPath);
  721.     }
  722.     else
  723.     {
  724.         /* Set audio buffer and queue size */
  725.         if (!SetBuffers( CDDA_BLOCKSIZE/(2*sizeof(UWORD)), 4 ))
  726.         {
  727.             Message("Unable to adjust sound driver's buffers and queue size.\n");
  728.         }
  729.         else
  730.         {
  731.             if (!StreamFormat( STREAM_16BIT_INTEL ))
  732.             {
  733.                 Message("Sound driver does not support 16bit INTEL stream format.\n");
  734.             }
  735.             else
  736.             {
  737.                 Success=TRUE;
  738.                 
  739.                 BUFBLOCKS=Buffers;
  740.                 for (i=0;i<3;i++)
  741.                 {
  742.                     if (!(Buffer[i]=AllocVec(BUFBLOCKS*CDDA_BLOCKSIZE, MEMF_CLEAR)))
  743.                     {
  744.                         Message("Cannot allocate sample buffer No. %ld.",(ULONG)i+1);
  745.                         Success=FALSE;
  746.                         break;
  747.                     }
  748.                 }
  749.             }
  750.         }
  751.     }
  752.     
  753.     if (!Success) DeInitDriver();
  754.     
  755.     return(Success);
  756. }
  757.  
  758.  
  759. /*******************************************************************************/
  760.  
  761. /* Deinit and close sound driver/buffers */
  762.  
  763. void DeInitDriver(void)
  764. {
  765.     UWORD i;
  766.     
  767.     if (DriverBase)
  768.     {
  769.         CloseLibrary(DriverBase);
  770.         DriverBase=NULL;
  771.     }
  772.     for (i=0;i<3;i++)
  773.     {
  774.         if (Buffer[i])
  775.         {
  776.             FreeVec(Buffer[i]);
  777.             Buffer[i]=NULL;
  778.         }
  779.     }
  780. }
  781.  
  782.  
  783. /*******************************************************************************/
  784.  
  785. /* Read CD-DA data into sound buffers */
  786.  
  787. void ReadBuffer(void)
  788. {
  789.     ULONG Blocks;
  790.     
  791.     /* Protect against sound driver */
  792.     SD_Lock();
  793.     /* Protect against SCSI driver */
  794.     Forbid();
  795.     
  796.     /* We must be in active state */
  797.     /* We want to have 2 requests pending */
  798.     /* Do not read if target LBA reached */
  799.     while (Active && Num_Reading<2 && LoadLBA<TargetLBA)
  800.     {
  801.         /* only load to empty buffers */
  802.         if (Status[Read_CB]==BUF_EMPTY)
  803.         {
  804.             /* Calculate the number of blocks to read */
  805.             Blocks=TargetLBA-LoadLBA;
  806.             if (Blocks>BUFBLOCKS) Blocks=BUFBLOCKS;
  807.             
  808.             /* Set buffer status */
  809.             Status[Read_CB]=BUF_LOADING;
  810.             
  811.             /* Increase number of pending reads */
  812.             Num_Reading++;
  813.             
  814.             /* Calc BufEndLBA/BufEndIndex (used for index incrementation) */
  815.             BufEndLBA[Read_CB]=LoadLBA+Blocks;
  816.             BufEndIndex[Read_CB]=EndIndex;
  817.             
  818.             /* Init LBA and LBN */
  819.             Read12[Read_CB].lba=LoadLBA;
  820.             Read12[Read_CB].lbn=Blocks;
  821.             
  822.             /* start asynchronous reading */
  823.             DoSCSI(    &AsyncSCSI_IO[Read_CB],
  824.                     &Read12[Read_CB], sizeof(Read12[Read_CB]),
  825.                     Buffer[Read_CB], Blocks*CDDA_BLOCKSIZE,
  826.                     SCSIF_READ, TRUE, NULL);
  827.             
  828.             /* increment LBA */
  829.             LoadLBA+=Blocks;
  830.             
  831.             /* increment buffer index */
  832.             Read_CB=(Read_CB+1)%3;
  833.             
  834.             /* Reached Target LBA? */
  835.             if (LoadLBA>=TargetLBA)
  836.             {
  837.                 /* Try to play next index */
  838.                 CD_ToIndex(CurrentIndex+1);
  839.             }
  840.         }
  841.         else break;
  842.     }
  843.     
  844.     /* Release protection against SCSI driver */
  845.     Permit();
  846.     /* Release protection against sound driver */
  847.     SD_Unlock();
  848. }
  849.  
  850.  
  851. /*******************************************************************************/
  852.  
  853. /* A buffer I/O has just finished (called by SCSI driver) */
  854.  
  855. void __saveds SCSIReply(void)
  856. {
  857.     /* Protect against sound driver */
  858.     SD_Lock();
  859.     
  860.     /* Change the priority of the SCSI driver */
  861.     
  862.     if (HighPri && HighPriSet==FALSE)
  863.     {
  864.         if (SCSITask=FindTask(NULL))
  865.         {
  866.             OldPri=SCSITask->tc_Node.ln_Pri;
  867.             SCSITask->tc_Node.ln_Pri=21;
  868.             HighPriSet=TRUE;
  869.             
  870.             /* This is A590/A2091 specific. It increases the */
  871.             /* priority of a second task as well. */
  872.             
  873.             if (!strcmp(SCSITask->tc_Node.ln_Name,"A590/A2091 IORequest handler"))
  874.             {
  875.                 if (AltSCSITask=FindTask("A590/A2091 SCSI handler"))
  876.                 {
  877.                     OldAltPri=AltSCSITask->tc_Node.ln_Pri;
  878.                     AltSCSITask->tc_Node.ln_Pri=22;
  879.                     AltPriSet=TRUE;
  880.                 }
  881.             }
  882.             /* Further controller-specific code may be added here */
  883.         }
  884.     }
  885.     
  886.     /* Remove replied message from port's list */
  887.     RemHead(&SyncReplyPort.mp_MsgList);
  888.     
  889.     /* Decrease number of pending reads */
  890.     Num_Reading--;
  891.     
  892.     /* store the number of returned bytes */
  893.     if (BytesRead[ReadReply_CB]=AsyncSCSICmd[ReadReply_CB].scsi_Actual)
  894.     {
  895.         /* Update buffer status */
  896.         Status[ReadReply_CB]=BUF_FILLED;
  897.     }
  898.     else
  899.     {
  900.         /* No data returned, buffer is empty! */
  901.         Status[ReadReply_CB]=BUF_EMPTY;
  902.     }
  903.     
  904.     /* (Re)Start replay if the previous and the current buffer is filled */
  905.     /* or if we have reached the end of the current track */
  906.     if ((Status[(ReadReply_CB+2)%3]==BUF_FILLED &&
  907.          Status[ ReadReply_CB     ]==BUF_FILLED) || LoadLBA>=TargetLBA)
  908.     {
  909.         Playing=TRUE;
  910.     }
  911.     
  912.     /* increment buffer index */
  913.     ReadReply_CB=(ReadReply_CB+1)%3;
  914.     
  915.     /* Read and play on */
  916.     ReadBuffer();
  917.     PlayBuffer();
  918.     
  919.     /* Release protection against sound driver */
  920.     SD_Unlock();
  921. }
  922.  
  923.  
  924. /*******************************************************************************/
  925.  
  926. /* Play the next filled sound buffers */
  927.  
  928. void PlayBuffer(void)
  929. {
  930.     UWORD Counter;
  931.     UWORD ActualQuality;
  932.     
  933.     /* Protect against sound driver */
  934.     SD_Lock();
  935.     /* Protect against SCSI driver */
  936.     Forbid();
  937.     
  938.     /* We must be in active and playing state */
  939.     /* We want to have 2 play requests pending */
  940.     /* and loop 3 times max (prevents lockups) */
  941.     for (Counter=0;Active && Playing && Num_Playing<2 && Counter<3;Counter++)
  942.     {
  943.         /* Only play filled buffers */
  944.         if (Status[Play_CB]==BUF_FILLED)
  945.         {
  946.             /* Calculate actual replay quality depending on hardware limits */
  947.             ActualQuality=QUALITY;
  948.             while ((FREQUENCY/ActualQuality)>AskFrequency(999999))
  949.             {
  950.                 ActualQuality++;
  951.             }
  952.             /* provide audio stream and check success */
  953.             if (ProvideStream(
  954.             /* left */
  955.                     Buffer[Play_CB],
  956.             /* right */
  957.                     Buffer[Play_CB]+1,
  958.             /* samples */
  959.                     BytesRead[Play_CB]/(2*sizeof(UWORD)*ActualQuality),
  960.             /* interleave */
  961.                     (sizeof(UWORD)*ActualQuality)-1,
  962.             /* frequency */
  963.                     FREQUENCY/ActualQuality,
  964.             /* reply routine */
  965.                     &SoundReply))
  966.             {
  967.                 /* Set buffer status to replay */
  968.                 Status[Play_CB]=BUF_PLAYING;
  969.                 
  970.                 /* Increase number of pending plays */
  971.                 Num_Playing++;
  972.             }
  973.         }
  974.         /* skip playing and empty buffers (e.g. caused by read errors) */
  975.         if (Status[Play_CB]==BUF_PLAYING || Status[Play_CB]==BUF_EMPTY)
  976.         {
  977.             /* increment buffer index */
  978.             Play_CB=(Play_CB+1)%3;
  979.         }
  980.         else break;
  981.     }
  982.     
  983.     /* Release protection against SCSI driver */
  984.     Permit();
  985.     /* Release protection against sound driver */
  986.     SD_Unlock();
  987. }
  988.  
  989.  
  990. /*******************************************************************************/
  991.  
  992. /* A sound buffer has just been played (called by sound driver) */
  993.  
  994. void __saveds SoundReply(void)
  995. {
  996.     /* Protect against SCSI driver */
  997.     Forbid();
  998.     
  999.     /* Decrease number of pending plays */
  1000.     Num_Playing--;
  1001.     
  1002.     /* Update buffer status */
  1003.     Status[PlayReply_CB]=BUF_EMPTY;
  1004.     
  1005.     /* Set LBA that was just played */
  1006.     PlayLBA=BufEndLBA[PlayReply_CB];
  1007.     
  1008.     /* Increment index if we have crossed a track boundary */
  1009.     while (    CurrentIndex < BufEndIndex[PlayReply_CB] && 
  1010.             BufEndLBA[PlayReply_CB] >= TOCData.desc[Program[CurrentIndex]-TOCData.lowtrack+1].lba)
  1011.     {
  1012.         CurrentIndex++;
  1013.     }
  1014.     
  1015.     /* Increment buffer index */
  1016.     PlayReply_CB=(PlayReply_CB+1)%3;
  1017.     
  1018.     /* Ran out of data? */
  1019.     if (Num_Playing==0)
  1020.     {
  1021.         /* Interrupt playing until buffers are full again */
  1022.         Playing=FALSE;
  1023.         
  1024.         /* Reached the end of the program? */
  1025.         if (Num_Reading==0 && LoadLBA>=TargetLBA)
  1026.         {
  1027.             /* Stop loading and playing */
  1028.             Active=FALSE;
  1029.             
  1030.             /* Restart track list */
  1031.             CD_ToIndex(1);
  1032.             
  1033.             /* Execute callback function */
  1034.             if (CallBack) (CallBack)();
  1035.         }
  1036.     }
  1037.     
  1038.     /* Read and play on */
  1039.     ReadBuffer();
  1040.     PlayBuffer();
  1041.     
  1042.     /* Release protection against SCSI driver */
  1043.     Permit();
  1044. }
  1045.  
  1046.  
  1047. /*******************************************************************************/
  1048.  
  1049. /* Execute a SCSI command (synchronous or asynchronous) */
  1050.  
  1051. UBYTE* SenseKeys[]=
  1052. {
  1053.     "NO SENSE",
  1054.     "RECOVERED ERROR",
  1055.     "NOT READY",
  1056.     "MEDIUM ERROR",
  1057.     "HARDWARE ERRROR",
  1058.     "ILLEGAL REQUEST",
  1059.     "UNIT ATTENTION",
  1060.     "DATA PROTECT",
  1061.     "BLANK CHECK",
  1062.     "VENDOR-SPECIFIC",
  1063.     "COPY ABORTED",
  1064.     "ABORTED COMMAND",
  1065.     "EQUAL",
  1066.     "VOLUME OVERFLOW",
  1067.     "MISCOMPARE",
  1068.     "RESERVED"
  1069. };
  1070.  
  1071. struct ErrorDefinition
  1072. {
  1073.     UWORD ErrorCode;
  1074.     UBYTE *ErrorName;
  1075. };
  1076.  
  1077.  
  1078. struct ErrorDefinition ErrorTable[]=
  1079. {
  1080.     0x1300,"ADDRESS MARK NOT FOUND FOR DATA FIELD",
  1081.     0x1200,"ADDRESS MARK NOT FOUND FOR ID FIELD",
  1082.     0x0011,"AUDIO PLAY OPERATION IN PROGRESS",
  1083.     0x0012,"AUDIO PLAY OPERATION PAUSED",
  1084.     0x0014,"AUDIO PLAY OPERATION STOPPED DUE TO ERROR",
  1085.     0x0013,"AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED",
  1086.     0x0004,"BEGINNING-OF-PARTITION/MEDIUM DETECTED",
  1087.     0x1404,"BLOCK SEQUENCE ERROR",
  1088.     0x3002,"CANNOT READ MEDIUM - INCOMPATIBLE FORMAT",
  1089.     0x3001,"CANNOT READ MEDIUM - UNKNOWN FORMAT",
  1090.     0x5200,"CARTRIDGE FAULT",
  1091.     0x3F02,"CHANGED OPERATING DEFINITION",
  1092.     0x1106,"CIRC UNRECOVERED ERROR",
  1093.     0x3003,"CLEANING CARTRIDGE INSTALLED",
  1094.     0x4A00,"COMMAND PHASE ERROR",
  1095.     0x2C00,"COMMAND SEQUENCE ERROR",
  1096.     0x2F00,"COMMANDS CLEARED BY ANOTHER INITIATOR",
  1097.     0x2B00,"COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT",
  1098.     0x4100,"DATA PATH FAILURE",
  1099.     0x4B00,"DATA PHASE ERROR",
  1100.     0x1107,"DATA RESYCHRONIZATION ERROR",
  1101.     0x1600,"DATA SYNCHRONIZATION MARK ERROR",
  1102.     0x1900,"DEFECT LIST ERROR",
  1103.     0x1903,"DEFECT LIST ERROR IN GROWN LIST",
  1104.     0x1902,"DEFECT LIST ERROR IN PRIMARY LIST",
  1105.     0x1901,"DEFECT LIST NOT AVAILABLE",
  1106.     0x1C00,"DEFECT LIST NOT FOUND",
  1107.     0x3201,"DEFECT LIST UPDATE FAILURE",
  1108.     0x6300,"END OF USER AREA ENCOUNTERED ON THIS TRACK",
  1109.     0x0005,"END-OF-DATA DETECTED",
  1110.     0x1403,"END-OF-DATA NOT FOUND",
  1111.     0x0002,"END-OF-PARTITION/MEDIUM DETECTED",
  1112.     0x5100,"ERASE FAILURE",
  1113.     0x0A00,"ERROR LOG OVERFLOW",
  1114.     0x1102,"ERROR TOO LONG TO CORRECT",
  1115.     0x0302,"EXCESSIVE WRITE ERRORS",
  1116.     0x3B07,"FAILED TO SENSE BOTTOM-OF-FORM",
  1117.     0x3B06,"FAILED TO SENSE TOP-OF-FORM",
  1118.     0x0001,"FILEMARK DETECTED",
  1119.     0x1402,"FILEMARK OR SETMARK NOT FOUND",
  1120.     0x0902,"FOCUS SERVO FAILURE",
  1121.     0x3101,"FORMAT COMMAND FAILED",
  1122.     0x5800,"GENERATION DOES NOT EXIST",
  1123.     0x1C02,"GROWN DEFECT LIST NOT FOUND",
  1124.     0x0006,"I/O PROCESS TERMINATED",
  1125.     0x1000,"ID CRC OR ECC ERROR",
  1126.     0x2200,"ILLEGAL FUNCTION",
  1127.     0x6400,"ILLEGAL MODE FOR THIS TRACK",
  1128.     0x2801,"IMPORT OR EXPORT ELEMENT ACCESSED",
  1129.     0x3000,"INCOMPATIBLE MEDIUM INSTALLED",
  1130.     0x1108,"INCOMPLETE BLOCK READ",
  1131.     0x4800,"INITIATOR DETECTED ERROR MESSAGE RECEIVED",
  1132.     0x3F03,"INQUIRY DATA HAS CHANGED",
  1133.     0x4400,"INTERNAL TARGET FAILURE",
  1134.     0x3D00,"INVALID BITS IN IDENTIFY MESSAGE",
  1135.     0x2C02,"INVALID COMBINATION OF WINDOWS SPECIFIED",
  1136.     0x2000,"INVALID COMMAND OPERATION CODE",
  1137.     0x2101,"INVALID ELEMENT ADDRESS",
  1138.     0x2400,"INVALID FIELD IN CDB",
  1139.     0x2600,"INVALID FIELD IN PARAMETER LIST",
  1140.     0x4900,"INVALID MESSAGE ERROR",
  1141.     0x1105,"L-EC UNCORRECTABLE ERROR",
  1142.     0x6000,"LAMP FAILURE",
  1143.     0x5B02,"LOG COUNTER AT MAXIMUM",
  1144.     0x5B00,"LOG EXCEPTION",
  1145.     0x5B03,"LOG LIST CODES EXHAUSTED",
  1146.     0x2A02,"LOG PARAMETERS CHANGED",
  1147.     0x2100,"LOGICAL BLOCK ADDRESS OUT OF RANGE",
  1148.     0x0800,"LOGICAL UNIT COMMUNICATION FAILURE",
  1149.     0x0802,"LOGICAL UNIT COMMUNICATION PARITY ERROR",
  1150.     0x0801,"LOGICAL UNIT COMMUNICATION TIME-OUT",
  1151.     0x0500,"LOGICAL UNIT DOES NOT RESPOND TO SELECTION",
  1152.     0x4C00,"LOGICAL UNIT FAILED SELF-CONFIGURATION",
  1153.     0x3E00,"LOGICAL UNIT HAS NOT SELF-CONFIGURED YET",
  1154.     0x0401,"LOGICAL UNIT IS IN PROCESS OF BECOMING READY",
  1155.     0x0400,"LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE",
  1156.     0x0404,"LOGICAL UNIT NOT READY, FORMAT IN PROGRESS",
  1157.     0x0402,"LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED",
  1158.     0x0403,"LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED",
  1159.     0x2500,"LOGICAL UNIT NOT SUPPORTED",
  1160.     0x1501,"MECHANICAL POSITIONING ERROR",
  1161.     0x5300,"MEDIA LOAD OR EJECT FAILED",
  1162.     0x3B0D,"MEDIUM DESTINATION ELEMENT FULL",
  1163.     0x3100,"MEDIUM FORMAT CORRUPTED",
  1164.     0x3A00,"MEDIUM NOT PRESENT",
  1165.     0x5302,"MEDIUM REMOVAL PREVENTED",
  1166.     0x3B0E,"MEDIUM SOURCE ELEMENT EMPTY",
  1167.     0x4300,"MESSAGE ERROR",
  1168.     0x3F01,"MICROCODE HAS BEEN CHANGED",
  1169.     0x1D00,"MISCOMPARE DURING VERIFY OPERATION",
  1170.     0x110A,"MISCORRECTED ERROR",
  1171.     0x2A01,"MODE PARAMETERS CHANGED",
  1172.     0x0700,"MULTIPLE PERIPHERAL DEVICES SELECTED",
  1173.     0x1103,"MULTIPLE READ ERRORS",
  1174.     0x0000,"NO ADDITIONAL SENSE INFORMATION",
  1175.     0x0015,"NO CURRENT AUDIO STATUS TO RETURN",
  1176.     0x3200,"NO DEFECT SPARE LOCATION AVAILABLE",
  1177.     0x1109,"NO GAP FOUND",
  1178.     0x0100,"NO INDEX/SECTOR SIGNAL",
  1179.     0x0600,"NO REFERENCE POSITION FOUND",
  1180.     0x0200,"NO SEEK COMPLETE",
  1181.     0x0301,"NO WRITE CURRENT",
  1182.     0x2800,"NOT READY TO READY TRANSITION (MEDIUM MAY HAVE CHANGED)",
  1183.     0x5A01,"OPERATOR MEDIUM REMOVAL REQUEST",
  1184.     0x5A00,"OPERATOR REQUEST OR STATE CHANGE INPUT (UNSPECIFIED)",
  1185.     0x5A03,"OPERATOR SELECTED WRITE PERMIT",
  1186.     0x5A02,"OPERATOR SELECTED WRITE PROTECT",
  1187.     0x6102,"OUT OF FOCUS",
  1188.     0x4E00,"OVERLAPPED COMMANDS ATTEMPTED",
  1189.     0x2D00,"OVERWRITE ERROR ON UPDATE IN PLACE",
  1190.     0x3B05,"PAPER JAM",
  1191.     0x1A00,"PARAMETER LIST LENGTH ERROR",
  1192.     0x2601,"PARAMETER NOT SUPPORTED",
  1193.     0x2602,"PARAMETER VALUE INVALID",
  1194.     0x2A00,"PARAMETERS CHANGED",
  1195.     0x0300,"PERIPHERAL DEVICE WRITE FAULT",
  1196.     0x5002,"POSITION ERROR RELATED TO TIMING",
  1197.     0x3B0C,"POSITION PAST BEGINNING OF MEDIUM",
  1198.     0x3B0B,"POSITION PAST END OF MEDIUM",
  1199.     0x1502,"POSITIONING ERROR DETECTED BY READ OF MEDIUM",
  1200.     0x2900,"POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",
  1201.     0x4200,"POWER-ON OR SELF-TEST FAILURE",
  1202.     0x1C01,"PRIMARY DEFECT LIST NOT FOUND",
  1203.     0x4000,"RAM FAILURE",
  1204.     0x1500,"RANDOM POSITIONING ERROR",
  1205.     0x3B0A,"READ PAST BEGINNING OF MEDIUM",
  1206.     0x3B09,"READ PAST END OF MEDIUM",
  1207.     0x1101,"READ RETRIES EXHAUSTED",
  1208.     0x1401,"RECORD NOT FOUND",
  1209.     0x1400,"RECORDED ENTITY NOT FOUND",
  1210.     0x1802,"RECOVERED DATA - DATA AUTO-REALLOCATED",
  1211.     0x1805,"RECOVERED DATA - RECOMMEND REASSIGNMENT",
  1212.     0x1705,"RECOVERED DATA USING PREVIOUS SECTOR ID",
  1213.     0x1803,"RECOVERED DATA WITH CIRC",
  1214.     0x1801,"RECOVERED DATA WITH ERROR CORRECTION AND RETRIES APPLIED",
  1215.     0x1800,"RECOVERED DATA WITH ERROR CORRECTION APPLIED",
  1216.     0x1804,"RECOVERED DATA WITH LEC",
  1217.     0x1703,"RECOVERED DATA WITH NEGATIVE HEAD OFFSET",
  1218.     0x1700,"RECOVERED DATA WITH NO ERROR CORRECTION APPLIED",
  1219.     0x1702,"RECOVERED DATA WITH POSITIVE HEAD OFFSET",
  1220.     0x1701,"RECOVERED DATA WITH RETRIES",
  1221.     0x1704,"RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED",
  1222.     0x1706,"RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED",
  1223.     0x1707,"RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT",
  1224.     0x1E00,"RECOVERED ID WITH ECC CORRECTION",
  1225.     0x3B08,"REPOSITION ERROR",
  1226.     0x3600,"RIBBON, INK, OR TONER FAILURE",
  1227.     0x3700,"ROUNDED PARAMETER",
  1228.     0x5C00,"RPL STATUS CHANGE",
  1229.     0x3900,"SAVING PARAMETERS NOT SUPPORTED",
  1230.     0x6200,"SCAN HEAD POSITIONING ERROR",
  1231.     0x4700,"SCSI PARITY ERROR",
  1232.     0x5400,"SCSI TO HOST SYSTEM INTERFACE FAILURE",
  1233.     0x4500,"SELECT OR RESELECT FAILURE",
  1234.     0x3B00,"SEQUENTIAL POSITIONING ERROR",
  1235.     0x0003,"SETMARK DETECTED",
  1236.     0x3B04,"SLEW FAILURE",
  1237.     0x0903,"SPINDLE SERVO FAILURE",
  1238.     0x5C02,"SPINDLES NOT SYNCHRONIZED",
  1239.     0x5C01,"SPINDLES SYNCHRONIZED",
  1240.     0x1B00,"SYNCHRONOUS DATA TRANSFER ERROR",
  1241.     0x5500,"SYSTEM RESOURCE FAILURE",
  1242.     0x3300,"TAPE LENGTH ERROR",
  1243.     0x3B03,"TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY",
  1244.     0x3B01,"TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM",
  1245.     0x3B02,"TAPE POSITION ERROR AT END-OF-MEDIUM",
  1246.     0x3F00,"TARGET OPERATING CONDITIONS HAVE CHANGED",
  1247.     0x5B01,"THRESHOLD CONDITION MET",
  1248.     0x2603,"THRESHOLD PARAMETERS NOT SUPPORTED",
  1249.     0x2C01,"TOO MANY WINDOWS SPECIFIED",
  1250.     0x0900,"TRACK FOLLOWING ERROR",
  1251.     0x0901,"TRACKING SERVO FAILURE",
  1252.     0x6101,"UNABLE TO ACQUIRE VIDEO",
  1253.     0x5700,"UNABLE TO RECOVER TABLE-OF-CONTENTS",
  1254.     0x5301,"UNLOAD TAPE FAILURE",
  1255.     0x1100,"UNRECOVERED READ ERROR",
  1256.     0x1104,"UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED",
  1257.     0x110B,"UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT",
  1258.     0x110C,"UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA",
  1259.     0x4600,"UNSUCCESSFUL SOFT RESET",
  1260.     0x5900,"UPDATED BLOCK READ",
  1261.     0x6100,"VIDEO ACQUISITION ERROR",
  1262.     0x5000,"WRITE APPEND ERROR",
  1263.     0x5001,"WRITE APPEND POSITION ERROR",
  1264.     0x0C00,"WRITE ERROR",
  1265.     0x0C02,"WRITE ERROR - AUTO REALLOCATION FAILED",
  1266.     0x0C01,"WRITE ERROR RECOVERED WITH AUTO REALLOCATION",
  1267.     0x2700,"WRITE PROTECTED",
  1268.     0xFFFF,"UNKNOWN ERROR CODE"
  1269. };
  1270.  
  1271.  
  1272. ULONG DoSCSI(struct IOStdReq *IORequest, APTR Command, ULONG CommandLength, APTR Buffer, ULONG Length, ULONG Flags, BOOL Asynchronous, UBYTE *ActivityName)
  1273. {
  1274.     struct SCSICmd *Cmd=(struct SCSICmd*)IORequest->io_Data;
  1275.     
  1276.     /* loop forever */
  1277.     for (;;)
  1278.     {
  1279.         Cmd->scsi_Command=Command;
  1280.         Cmd->scsi_CmdLength=CommandLength;
  1281.         Cmd->scsi_Data=Buffer;
  1282.         Cmd->scsi_Length=Length;
  1283.         Cmd->scsi_Flags=Flags;
  1284.         Cmd->scsi_Actual=
  1285.         Cmd->scsi_CmdActual=
  1286.         Cmd->scsi_SenseActual=0;
  1287.         
  1288.         if (Cmd->scsi_SenseData)
  1289.         {
  1290.             Cmd->scsi_Flags |= SCSIF_AUTOSENSE;
  1291.         }
  1292.         
  1293.         IORequest->io_Flags=0;
  1294.         IORequest->io_Length=sizeof(struct SCSICmd);
  1295.         IORequest->io_Command=HD_SCSICMD;
  1296.         
  1297.         if (Asynchronous)
  1298.         {
  1299.             BeginIO(IORequest);
  1300.             break;
  1301.         }
  1302.         else
  1303.         {
  1304.             DoIO(IORequest);
  1305.             
  1306.             if (Cmd->scsi_SenseActual)
  1307.             {
  1308.                 struct EasyStruct Req={    sizeof (struct EasyStruct),
  1309.                                         0,
  1310.                                         "SCSI error",
  1311.                                         "SCSI unit reports error while %s\n%s: %s",
  1312.                                         "Retry|Cancel"};
  1313.                 
  1314.                 struct SenseData *SD;
  1315.                 if (SD=(struct SenseData*)Cmd->scsi_SenseData)
  1316.                 {
  1317.                     BOOL OpenIntui=FALSE;
  1318.                     UBYTE *KeyName=SenseKeys[SD->sensekey&0xf];
  1319.                     UBYTE *AddName="NO ADDITIONAL ERROR CODE";
  1320.                     
  1321.                     if (SD->addlength>=6)
  1322.                     {
  1323.                         struct ErrorDefinition *ED;
  1324.                         for(ED=ErrorTable;ED->ErrorCode!=0xffff;ED++)
  1325.                         {
  1326.                             if (ED->ErrorCode==SD->additionalsense) break;
  1327.                         }
  1328.                         AddName=ED->ErrorName;
  1329.                     }
  1330.                     
  1331.                     if (!IntuitionBase)
  1332.                     {
  1333.                         IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",37);
  1334.                         OpenIntui=TRUE;
  1335.                     }
  1336.                     
  1337.                     if (IntuitionBase)
  1338.                     {
  1339.                         if (!EasyRequest(NULL, &Req, NULL, ActivityName, KeyName, AddName))
  1340.                         {
  1341.                             break;
  1342.                         }
  1343.                     }
  1344.                     
  1345.                     if (IntuitionBase && OpenIntui)
  1346.                     {
  1347.                         CloseLibrary((struct Library*)IntuitionBase);
  1348.                         IntuitionBase=NULL;
  1349.                     }
  1350.                 }
  1351.             }
  1352.             else break;
  1353.         }
  1354.     }
  1355.     return(Cmd->scsi_Actual);
  1356. }
  1357.  
  1358.  
  1359. /*******************************************************************************/
  1360.  
  1361. /* Show a message to the user */
  1362.  
  1363. void __stdargs Message(UBYTE *Msg,...)
  1364. {
  1365.     va_list Arg;
  1366.     struct EasyStruct Req={sizeof(struct EasyStruct),0,"CDPlayer message",0,"Okay"};
  1367.     Req.es_TextFormat=Msg;
  1368.     va_start(Arg,Msg);
  1369.     
  1370.     if (IntuitionBase)
  1371.     {
  1372.         EasyRequestArgs(NULL,&Req,0,Arg);
  1373.     }
  1374.     else
  1375.     {
  1376.         VPrintf(Msg,Arg);
  1377.         Printf("\n");
  1378.     }
  1379.     
  1380.     va_end(Arg);
  1381. }
  1382.