home *** CD-ROM | disk | FTP | other *** search
-
- /********************************************
- * CD Audio Player using 14bit sound driver *
- * for Toshiba 4101 CDRom and compatible *
- * (c) 1995 by Christian Buchner *
- ********************************************
- *
- * CDPlayer.c
- */
-
- /* Note: TAB SIZE = 4 */
-
-
- /* Includes */
-
- #include <proto/dos.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <clib/alib_stdio_protos.h>
- #include <libraries/dos.h>
- #include <intuition/intuition.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <devices/scsidisk.h>
- #include <string.h>
- #include <stdarg.h>
-
- #include "//14bit.driver/Source/Driver_protos.h"
- #include "//14bit.driver/Source/Driver_pragmas.h"
- #include "//14bit.driver/Source/Driver.h"
-
-
- /* Prototypes */
-
- #include "CDPlayer_Protos.h"
-
-
- /* Version String */
-
- char *VersionString = VERSION_STRING;
-
-
- /* CDDA constants */
-
- #define CDDA_BLOCKSIZE 2352 /* size of one CDDA block */
- #define ONE_SECOND 75 /* blocks per second (75) */
-
-
- /* Values defining sound buffers and sound output */
-
- ULONG BUFBLOCKS=20; /* Buffer size in blocks (allocated 3 times) */
- ULONG FREQUENCY=44100; /* Desired replay frequency */
- ULONG QUALITY=1; /* 1 for maximum quality (44khz) */
-
-
- /* Library bases */
-
- struct DosLibrary *DOSBase;
- struct IntuitionBase *IntuitionBase;
- struct Library *DriverBase;
-
-
- /* Synchronous SCSI IO */
-
- LONG SyncSigBit= -1;
- struct MsgPort SyncReplyPort;
- struct IOStdReq SyncSCSI_IO;
- struct SCSICmd SyncSCSICmd;
-
-
- /* Asynchronous SCSI IO */
-
- struct MsgPort AsyncReplyPort; /* note: only ONE port necessary */
- struct IOStdReq AsyncSCSI_IO[3];
- struct SCSICmd AsyncSCSICmd[3];
-
-
- /* Definition of the buffer states */
-
- enum States
- {
- BUF_EMPTY,
- BUF_LOADING,
- BUF_FILLED,
- BUF_PLAYING,
- };
-
-
- /* Status variables used for replay */
-
- ULONG Read_CB; /* Read current buffer */
- ULONG ReadReply_CB; /* Read reply current buffer */
- ULONG Play_CB; /* Play current buffer */
- ULONG PlayReply_CB; /* Play reply cuttent buffer */
-
- ULONG LoadLBA; /* the block currently being loaded */
- ULONG TargetLBA; /* the end block for current (continuous) replay */
- ULONG PlayLBA; /* the LBA that was just played */
-
- UWORD Status[3]; /* the buffer states */
- UWORD *Buffer[3]; /* pointers to the buffers themselves */
- ULONG BytesRead[3]; /* buffer contents, only valid for BUF_FILLED */
- ULONG BufEndLBA[3]; /* The end LBA of the buffers plus one */
- UWORD BufEndIndex[3]; /* The EndIndex value when the buffers were loaded */
-
- UWORD Num_Playing; /* number of pending play requests */
- UWORD Num_Reading; /* number of pending read requests */
- BOOL Active; /* allow reading and playing of data */
- BOOL Playing; /* allow sound output (used for synchronization) */
-
-
- /* Priority management (PromotePri flag) */
-
- BOOL HighPri; /* scsi driver's priority is to be "promoted" */
- BOOL HighPriSet; /* value in OldPri is valid */
- UBYTE OldPri; /* old priority of the scsi driver */
- struct Task *SCSITask; /* the task that OldPri belongs to */
-
- BOOL AltPriSet; /* This is for A2091 specifically */
- UBYTE OldAltPri;
- struct Task *AltSCSITask;
-
-
- /* Variables for Program management */
-
- UWORD MaxIndex; /* number of entries in the program (=maximum index)*/
- UBYTE Program[129]; /* the program itself, element [0] is not used! */
- UWORD CurrentIndex; /* the current (playing) index */
- UWORD EndIndex; /* the last index of continuous replay */
- void (*CallBack)(void); /* callback function when program end reached */
-
-
- /* SCSI command and mode structures */
-
- struct Read12
- {
- UBYTE cmd; /* READ(12) SCSI command 0xA8 */
- UBYTE pad_a; /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
- ULONG lba; /* logical block address MSB, , ,LSB */
- ULONG lbn; /* number of blocks to transfer MSB, , ,LSB */
- UBYTE subcode; /* special sub code selector (only for SONY!)
- * 0: normal 2352
- * 1: 2368
- * 2: 2448
- * 3: 96 bytes */
- UBYTE cntrl; /* Control */
- };
-
- struct ModeSense
- {
- UBYTE cmd;
- UBYTE pad_a;
- UBYTE page;
- UBYTE reserved;
- UBYTE alloclen;
- UBYTE cntrl;
- };
-
- struct ModeSelect
- {
- UBYTE cmd;
- UBYTE pageformat;
- UBYTE reserved_a;
- UBYTE reserved_b;
- UBYTE plistlen;
- UBYTE cntrl;
- };
-
- struct ModeData
- {
- /* 4 Byte Mode Parameter Header (Table 7-61) */
- UBYTE mode_data_length;
- UBYTE medium_type;
- UBYTE device_specific_parameter;
- UBYTE block_descriptor_length;
- /* 8 Byte Mode Parameter Block Descriptor (Table 7-63) */
- UBYTE density;
- UBYTE num_blocks_H;
- UBYTE num_blocks_M;
- UBYTE num_blocks_L;
- ULONG block_length;
- };
-
- struct Inquiry
- {
- UBYTE cmd;
- UBYTE pad_a;
- UBYTE page;
- UBYTE reserved;
- UBYTE alloclen;
- UBYTE cntrl;
- };
-
- struct InquiryData
- {
- UBYTE pdevtype;
- UBYTE rmb_devtypmod;
- UBYTE versions;
- UBYTE rdformat;
- UBYTE addlength;
- UBYTE reserved_a;
- UBYTE reserved_b;
- UBYTE lotsofbits;
- UBYTE vendor[8];
- UBYTE prod_id[16];
- UBYTE revision[4];
- UBYTE specific[20];
- UBYTE reserved[40];
- };
-
- struct ReadTOC
- {
- UBYTE cmd;
- UBYTE misc;
- ULONG reserved;
- UBYTE starttrack;
- UBYTE alloclenHI;
- UBYTE alloclenLO;
- UBYTE control;
- };
-
- struct TrackDesc
- {
- UBYTE reserved;
- UBYTE adrctrl;
- UBYTE trackno;
- UBYTE reserved2;
- ULONG lba;
- };
-
- struct TOCData
- {
- UWORD length;
- UBYTE lowtrack;
- UBYTE hightrack;
- struct TrackDesc desc[100];
- };
-
- struct SenseData
- {
- UBYTE errcode;
- UBYTE segnum;
- UBYTE sensekey;
- UBYTE information[4];
- UBYTE addlength;
- UBYTE specificinfo[4];
- UWORD additionalsense;
- UBYTE unitcode;
- UBYTE sensekeyspec[3];
- UBYTE space[20];
- };
-
-
- /* SCSI command and data bytes (somewhat pre-initialized) */
-
- struct SenseData SyncSenseData;
- struct SenseData AsyncSenseData[3];
-
- struct Read12 Read12[3]=
-
- { 0xA8, 0x00, 0, 0, 0, 0,
- 0xA8, 0x00, 0, 0, 0, 0,
- 0xA8, 0x00, 0, 0, 0, 0 };
-
- struct InquiryData InquiryData;
- struct Inquiry Inquiry={0x12, 0x00, 0, 0, sizeof(InquiryData), 0};
-
- struct ModeData OldModePage;
- struct ModeData NewModePage={0,0,0,8, 0x82,0,0,0,CDDA_BLOCKSIZE};
-
- struct ModeSense ModeSense ={0x1A, 0, 1, 0, sizeof(OldModePage), 0};
- struct ModeSelect ModeSelect={0x15, 0x10, 0, 0, sizeof(NewModePage), 0};
-
- struct TOCData TOCData;
- struct ReadTOC ReadTOC={0x43, 0, 0, 0, sizeof(TOCData)>>8, sizeof(TOCData)&0xff, 0};
-
-
- /*******************************************************************************/
-
- /* Generate a program from a ReadArgs style tracklist */
-
- UWORD CD_SetProgram(ULONG **tracklist, void (*callback)(void))
- {
- ULONG Track;
-
- /* Initialize callback hook (called when program is finished) */
- CallBack=callback;
-
- /* Generate a full program, if tracklist or *tracklist is NULL */
- if (tracklist==NULL || *tracklist==NULL)
- {
- /* Loop all tracks */
- for (MaxIndex=0,Track=TOCData.lowtrack;Track<=TOCData.hightrack;Track++)
- {
- if (CheckAudio(Track))
- {
- MaxIndex++;
- Program[MaxIndex]=Track;
- }
- }
- }
- else
- {
- /* Generate a program from all playable tracks in the tracklist */
- for (MaxIndex=0;*tracklist;tracklist++)
- {
- if (CheckAudio(**tracklist))
- {
- MaxIndex++;
- Program[MaxIndex]= **tracklist;
- }
- }
- }
-
- /* Restart track list */
- CD_ToIndex(1);
-
- return(MaxIndex);
- }
-
-
- /*******************************************************************************/
-
- /* Position at specified index in program */
-
- UWORD CD_ToIndex(UWORD Index)
- {
- UWORD Result=0;
-
- if (Index>=1 && Index<=MaxIndex)
- {
- Result=CurrentIndex=Index;
-
- /* Set start LBAs for replay */
- LoadLBA=TargetLBA=PlayLBA=TOCData.desc[Program[Index]-TOCData.lowtrack].lba;
-
- /* Find out how many tracks can be played continuously */
- while(Index<=MaxIndex && TargetLBA==TOCData.desc[Program[Index]-TOCData.lowtrack].lba)
- {
- EndIndex=Index;
- TargetLBA=TOCData.desc[Program[Index]-TOCData.lowtrack+1].lba;
- Index++;
- }
- }
-
- return(Result);
- }
-
-
- /*******************************************************************************/
-
- /* Get Index of currently positioned title */
-
- UWORD CD_CurrentIndex(void)
- {
- return(CurrentIndex);
- }
-
-
- /*******************************************************************************/
-
- /* Get currently positioned title */
-
- UWORD CD_CurrentTrack(void)
- {
- return(Program[CurrentIndex]);
- }
-
-
- /*******************************************************************************/
-
- /* Get current position in track (returned in LBAs) */
-
- ULONG CD_CurrentPosition(void)
- {
- return(PlayLBA-TOCData.desc[Program[CurrentIndex]-TOCData.lowtrack].lba);
- }
-
-
- /*******************************************************************************/
-
- /* Skip to next index */
-
- UWORD CD_NextIndex(void)
- {
- BOOL Restart;
- UWORD ResIndex=0;
-
- if (CurrentIndex<MaxIndex)
- {
- Restart=CD_Abort();
-
- ResIndex=CD_ToIndex(CurrentIndex+1);
-
- if (Restart) CD_Start();
- }
- return(ResIndex);
- }
-
-
- /*******************************************************************************/
-
- /* Skip to previous index */
-
- UWORD CD_PrevIndex(void)
- {
- BOOL Restart;
- UWORD ResIndex=0;
-
- if (CurrentIndex>1)
- {
- Restart=CD_Abort();
-
- ResIndex=CD_ToIndex(CurrentIndex-1);
-
- if (Restart) CD_Start();
- }
- return(ResIndex);
- }
-
-
- /*******************************************************************************/
-
- void CD_Skip(WORD seconds)
- {
- BOOL Restart;
- LONG LBA;
-
- Restart=CD_Abort();
-
- LBA=LoadLBA+(LONG)ONE_SECOND*seconds;
- if (LBA < 0) LBA=0;
- if (LBA > TargetLBA) LBA=TargetLBA;
- LoadLBA=LBA;
-
- if (Restart) CD_Start();
- }
-
-
- /*******************************************************************************/
-
- /* Initialize buffers */
-
- void CD_Init(void)
- {
- /* Init flags */
- Active=FALSE;
- Playing=FALSE;
-
- /* Reset buffer status */
- Status[0]=Status[1]=Status[2]=BUF_EMPTY;
-
- /* Reset current buffer counters */
- Read_CB=0;
- ReadReply_CB=0;
- Play_CB=0;
- PlayReply_CB=0;
- }
-
-
- /*******************************************************************************/
-
- /* Start playing */
-
- void CD_Start(void)
- {
- Active=TRUE;
-
- /* Start playing */
- ReadBuffer();
- }
-
-
- /*******************************************************************************/
-
- /* Abort playing and wait until replay has finished */
- /* returns TRUE if CD was actually playing */
-
- BOOL CD_Abort(void)
- {
- UWORD i;
- BOOL OldActive=Active;
-
- /* Now we have to stop playing */
- Active=FALSE;
- Playing=FALSE;
-
- /* Abort sound replay */
- FlushStream();
-
- /* Abort reading */
- for (i=0;i<2;i++)
- {
- if (Status[i]==BUF_LOADING)
- {
- AbortIO((struct IORequest*)&AsyncSCSI_IO[i]);
- }
- }
-
- /* Wait until buffer status is idle */
- while( Num_Reading!=0 || Num_Playing!=0 ||
- (Status[0]!=BUF_EMPTY && Status[0]!=BUF_FILLED) ||
- (Status[1]!=BUF_EMPTY && Status[1]!=BUF_FILLED) ||
- (Status[2]!=BUF_EMPTY && Status[2]!=BUF_FILLED) )
- {
- Delay(10);
- }
-
- /* Reinitialize buffers */
- CD_Init();
-
- return(OldActive);
- }
-
-
- /*******************************************************************************/
-
- /* Pause replay */
-
- void CD_Pause(void)
- {
- PauseStream();
- }
-
-
- /*******************************************************************************/
-
- /* Resume replay */
-
- void CD_Resume(void)
- {
- ResumeStream();
- }
-
-
- /*******************************************************************************/
-
- /* Change frequency */
-
- void CD_Frequency(ULONG frequency)
- {
- FREQUENCY=frequency;
- }
-
-
- /*******************************************************************************/
-
- /* Change quality */
-
- void CD_Quality(ULONG quality)
- {
- QUALITY=quality;
- }
-
-
- /*******************************************************************************/
-
- /* Check if a track can be played */
-
- BOOL CheckAudio(ULONG Track)
- {
- if (Track>=TOCData.lowtrack && Track<=TOCData.hightrack)
- {
- if ((TOCData.desc[Track-TOCData.lowtrack].adrctrl & 0xf)==0)
- {
- return(TRUE);
- }
- }
- return(FALSE);
- }
-
-
- /*******************************************************************************/
-
- /* Open and initialize CDRom */
-
- BOOL OpenSCSI(UBYTE *Device, ULONG Unit, BOOL PromotePri)
- {
- BOOL Success=FALSE;
- UWORD i;
-
- /* Store HighPri flag */
- HighPri=PromotePri;
-
- /* Init synchronous SCSI IO */
-
- SyncReplyPort.mp_Node.ln_Type=NT_MSGPORT;
- SyncReplyPort.mp_Flags=PA_SIGNAL;
- SyncReplyPort.mp_SigTask=FindTask(NULL);
- NewList(&SyncReplyPort.mp_MsgList);
-
- if ((SyncSigBit=SyncReplyPort.mp_SigBit=AllocSignal(-1))!=-1)
- {
- SyncSCSI_IO.io_Message.mn_Node.ln_Type=NT_MESSAGE;
- SyncSCSI_IO.io_Message.mn_Length=sizeof(struct IOStdReq);
-
- SyncSCSI_IO.io_Message.mn_ReplyPort= &SyncReplyPort;
- SyncSCSI_IO.io_Data= &SyncSCSICmd;
-
- SyncSCSICmd.scsi_SenseData=(UBYTE*)&SyncSenseData;
- SyncSCSICmd.scsi_SenseLength=sizeof(SyncSenseData);
-
- /* Init asynchronous SCSI IO */
-
- AsyncReplyPort.mp_Node.ln_Type=NT_MSGPORT;
- AsyncReplyPort.mp_Flags=PF_ACTION;
- AsyncReplyPort.mp_SigTask=(APTR)&SCSIReply;
- NewList(&AsyncReplyPort.mp_MsgList);
-
- for (i=0;i<3;i++)
- {
- AsyncSCSI_IO[i].io_Message.mn_Node.ln_Type=NT_MESSAGE;
- AsyncSCSI_IO[i].io_Message.mn_Length=sizeof(struct IOStdReq);
-
- AsyncSCSI_IO[i].io_Message.mn_ReplyPort= &AsyncReplyPort;
- AsyncSCSI_IO[i].io_Data= &AsyncSCSICmd[i];
-
- AsyncSCSICmd[i].scsi_SenseData=(UBYTE*)&AsyncSenseData[i];
- AsyncSCSICmd[i].scsi_SenseLength=sizeof(AsyncSenseData[i]);
- }
-
- if (OpenDevice(Device,Unit,(struct IORequest*)&SyncSCSI_IO,0))
- {
- Message("Cannot open '%s' unit %ld.",Device,Unit);
- }
- else
- {
- for (i=0;i<3;i++)
- {
- AsyncSCSI_IO[i].io_Device=SyncSCSI_IO.io_Device;
- AsyncSCSI_IO[i].io_Unit=SyncSCSI_IO.io_Unit;
- }
- if (DoSCSI(&SyncSCSI_IO, &Inquiry, sizeof(Inquiry), &InquiryData, sizeof(InquiryData), SCSIF_READ, FALSE, "reading inquiry data"))
- {
- if (InquiryData.pdevtype != 5)
- {
- Message("'%s' unit %ld is not a CDRom!",Device,Unit);
- }
- else
- {
- /* Read Table of Contents */
- if (!(DoSCSI(&SyncSCSI_IO, &ReadTOC, sizeof(ReadTOC), &TOCData, sizeof(TOCData), SCSIF_READ, FALSE, "reading table of contents")))
- {
- Message("Cannot read Table of Contents!");
- }
- else
- {
- /* Prepare CDRom for CDDA data transfer */
- DoSCSI(&SyncSCSI_IO, &ModeSense, sizeof(ModeSense), &OldModePage, sizeof(OldModePage), SCSIF_READ, FALSE, "reading mode page");
- DoSCSI(&SyncSCSI_IO, &ModeSelect, sizeof(ModeSelect), &NewModePage, sizeof(NewModePage), SCSIF_WRITE, FALSE, "selecting CD-DA data format");
-
- /* Initialize buffers */
- CD_Init();
-
- Success=TRUE;
- }
- }
- }
- }
- }
- if (!Success) CloseSCSI();
-
- return(Success);
- }
-
-
- /*******************************************************************************/
-
- /* Reset and close CDRom */
-
- void CloseSCSI(void)
- {
- /* Reset priority of the SCSI driver task(s) */
- if (HighPriSet && SCSITask)
- {
- SCSITask->tc_Node.ln_Pri=OldPri;
- HighPriSet=FALSE;
-
- if (AltPriSet && AltSCSITask)
- {
- AltSCSITask->tc_Node.ln_Pri=OldAltPri;
- AltPriSet=FALSE;
- }
- }
-
- if (SyncSCSI_IO.io_Device)
- {
- /* Reset CDRom transfer mode */
- if (OldModePage.mode_data_length>0)
- {
- OldModePage.mode_data_length=0;
- DoSCSI(&SyncSCSI_IO, &ModeSelect, sizeof(ModeSelect), &OldModePage, sizeof(OldModePage), SCSIF_WRITE, FALSE, "resetting data format");
- }
- CloseDevice((struct IORequest*)&SyncSCSI_IO);
- SyncSCSI_IO.io_Device=NULL;
- }
- if (SyncSigBit!=-1)
- {
- FreeSignal(SyncSigBit);
- SyncSigBit= -1;
- }
- }
-
-
- /*******************************************************************************/
-
- /* Open and Init sound driver/buffers */
-
- BOOL InitDriver(UBYTE *Driver, ULONG Buffers)
- {
- BOOL Success=FALSE;
- UBYTE DriverPath[80];
- UWORD i;
-
- strcpy(DriverPath, "DEVS:SoundDrivers/");
- strcat(DriverPath, Driver);
-
- if (!(DriverBase=OpenLibrary(DriverPath,0)))
- {
- Message("Cannot open sound driver '%s'.",DriverPath);
- }
- else
- {
- /* Set audio buffer and queue size */
- if (!SetBuffers( CDDA_BLOCKSIZE/(2*sizeof(UWORD)), 4 ))
- {
- Message("Unable to adjust sound driver's buffers and queue size.\n");
- }
- else
- {
- if (!StreamFormat( STREAM_16BIT_INTEL ))
- {
- Message("Sound driver does not support 16bit INTEL stream format.\n");
- }
- else
- {
- Success=TRUE;
-
- BUFBLOCKS=Buffers;
- for (i=0;i<3;i++)
- {
- if (!(Buffer[i]=AllocVec(BUFBLOCKS*CDDA_BLOCKSIZE, MEMF_CLEAR)))
- {
- Message("Cannot allocate sample buffer No. %ld.",(ULONG)i+1);
- Success=FALSE;
- break;
- }
- }
- }
- }
- }
-
- if (!Success) DeInitDriver();
-
- return(Success);
- }
-
-
- /*******************************************************************************/
-
- /* Deinit and close sound driver/buffers */
-
- void DeInitDriver(void)
- {
- UWORD i;
-
- if (DriverBase)
- {
- CloseLibrary(DriverBase);
- DriverBase=NULL;
- }
- for (i=0;i<3;i++)
- {
- if (Buffer[i])
- {
- FreeVec(Buffer[i]);
- Buffer[i]=NULL;
- }
- }
- }
-
-
- /*******************************************************************************/
-
- /* Read CD-DA data into sound buffers */
-
- void ReadBuffer(void)
- {
- ULONG Blocks;
-
- /* Protect against sound driver */
- SD_Lock();
- /* Protect against SCSI driver */
- Forbid();
-
- /* We must be in active state */
- /* We want to have 2 requests pending */
- /* Do not read if target LBA reached */
- while (Active && Num_Reading<2 && LoadLBA<TargetLBA)
- {
- /* only load to empty buffers */
- if (Status[Read_CB]==BUF_EMPTY)
- {
- /* Calculate the number of blocks to read */
- Blocks=TargetLBA-LoadLBA;
- if (Blocks>BUFBLOCKS) Blocks=BUFBLOCKS;
-
- /* Set buffer status */
- Status[Read_CB]=BUF_LOADING;
-
- /* Increase number of pending reads */
- Num_Reading++;
-
- /* Calc BufEndLBA/BufEndIndex (used for index incrementation) */
- BufEndLBA[Read_CB]=LoadLBA+Blocks;
- BufEndIndex[Read_CB]=EndIndex;
-
- /* Init LBA and LBN */
- Read12[Read_CB].lba=LoadLBA;
- Read12[Read_CB].lbn=Blocks;
-
- /* start asynchronous reading */
- DoSCSI( &AsyncSCSI_IO[Read_CB],
- &Read12[Read_CB], sizeof(Read12[Read_CB]),
- Buffer[Read_CB], Blocks*CDDA_BLOCKSIZE,
- SCSIF_READ, TRUE, NULL);
-
- /* increment LBA */
- LoadLBA+=Blocks;
-
- /* increment buffer index */
- Read_CB=(Read_CB+1)%3;
-
- /* Reached Target LBA? */
- if (LoadLBA>=TargetLBA)
- {
- /* Try to play next index */
- CD_ToIndex(CurrentIndex+1);
- }
- }
- else break;
- }
-
- /* Release protection against SCSI driver */
- Permit();
- /* Release protection against sound driver */
- SD_Unlock();
- }
-
-
- /*******************************************************************************/
-
- /* A buffer I/O has just finished (called by SCSI driver) */
-
- void __saveds SCSIReply(void)
- {
- /* Protect against sound driver */
- SD_Lock();
-
- /* Change the priority of the SCSI driver */
-
- if (HighPri && HighPriSet==FALSE)
- {
- if (SCSITask=FindTask(NULL))
- {
- OldPri=SCSITask->tc_Node.ln_Pri;
- SCSITask->tc_Node.ln_Pri=21;
- HighPriSet=TRUE;
-
- /* This is A590/A2091 specific. It increases the */
- /* priority of a second task as well. */
-
- if (!strcmp(SCSITask->tc_Node.ln_Name,"A590/A2091 IORequest handler"))
- {
- if (AltSCSITask=FindTask("A590/A2091 SCSI handler"))
- {
- OldAltPri=AltSCSITask->tc_Node.ln_Pri;
- AltSCSITask->tc_Node.ln_Pri=22;
- AltPriSet=TRUE;
- }
- }
- /* Further controller-specific code may be added here */
- }
- }
-
- /* Remove replied message from port's list */
- RemHead(&SyncReplyPort.mp_MsgList);
-
- /* Decrease number of pending reads */
- Num_Reading--;
-
- /* store the number of returned bytes */
- if (BytesRead[ReadReply_CB]=AsyncSCSICmd[ReadReply_CB].scsi_Actual)
- {
- /* Update buffer status */
- Status[ReadReply_CB]=BUF_FILLED;
- }
- else
- {
- /* No data returned, buffer is empty! */
- Status[ReadReply_CB]=BUF_EMPTY;
- }
-
- /* (Re)Start replay if the previous and the current buffer is filled */
- /* or if we have reached the end of the current track */
- if ((Status[(ReadReply_CB+2)%3]==BUF_FILLED &&
- Status[ ReadReply_CB ]==BUF_FILLED) || LoadLBA>=TargetLBA)
- {
- Playing=TRUE;
- }
-
- /* increment buffer index */
- ReadReply_CB=(ReadReply_CB+1)%3;
-
- /* Read and play on */
- ReadBuffer();
- PlayBuffer();
-
- /* Release protection against sound driver */
- SD_Unlock();
- }
-
-
- /*******************************************************************************/
-
- /* Play the next filled sound buffers */
-
- void PlayBuffer(void)
- {
- UWORD Counter;
- UWORD ActualQuality;
-
- /* Protect against sound driver */
- SD_Lock();
- /* Protect against SCSI driver */
- Forbid();
-
- /* We must be in active and playing state */
- /* We want to have 2 play requests pending */
- /* and loop 3 times max (prevents lockups) */
- for (Counter=0;Active && Playing && Num_Playing<2 && Counter<3;Counter++)
- {
- /* Only play filled buffers */
- if (Status[Play_CB]==BUF_FILLED)
- {
- /* Calculate actual replay quality depending on hardware limits */
- ActualQuality=QUALITY;
- while ((FREQUENCY/ActualQuality)>AskFrequency(999999))
- {
- ActualQuality++;
- }
- /* provide audio stream and check success */
- if (ProvideStream(
- /* left */
- Buffer[Play_CB],
- /* right */
- Buffer[Play_CB]+1,
- /* samples */
- BytesRead[Play_CB]/(2*sizeof(UWORD)*ActualQuality),
- /* interleave */
- (sizeof(UWORD)*ActualQuality)-1,
- /* frequency */
- FREQUENCY/ActualQuality,
- /* reply routine */
- &SoundReply))
- {
- /* Set buffer status to replay */
- Status[Play_CB]=BUF_PLAYING;
-
- /* Increase number of pending plays */
- Num_Playing++;
- }
- }
- /* skip playing and empty buffers (e.g. caused by read errors) */
- if (Status[Play_CB]==BUF_PLAYING || Status[Play_CB]==BUF_EMPTY)
- {
- /* increment buffer index */
- Play_CB=(Play_CB+1)%3;
- }
- else break;
- }
-
- /* Release protection against SCSI driver */
- Permit();
- /* Release protection against sound driver */
- SD_Unlock();
- }
-
-
- /*******************************************************************************/
-
- /* A sound buffer has just been played (called by sound driver) */
-
- void __saveds SoundReply(void)
- {
- /* Protect against SCSI driver */
- Forbid();
-
- /* Decrease number of pending plays */
- Num_Playing--;
-
- /* Update buffer status */
- Status[PlayReply_CB]=BUF_EMPTY;
-
- /* Set LBA that was just played */
- PlayLBA=BufEndLBA[PlayReply_CB];
-
- /* Increment index if we have crossed a track boundary */
- while ( CurrentIndex < BufEndIndex[PlayReply_CB] &&
- BufEndLBA[PlayReply_CB] >= TOCData.desc[Program[CurrentIndex]-TOCData.lowtrack+1].lba)
- {
- CurrentIndex++;
- }
-
- /* Increment buffer index */
- PlayReply_CB=(PlayReply_CB+1)%3;
-
- /* Ran out of data? */
- if (Num_Playing==0)
- {
- /* Interrupt playing until buffers are full again */
- Playing=FALSE;
-
- /* Reached the end of the program? */
- if (Num_Reading==0 && LoadLBA>=TargetLBA)
- {
- /* Stop loading and playing */
- Active=FALSE;
-
- /* Restart track list */
- CD_ToIndex(1);
-
- /* Execute callback function */
- if (CallBack) (CallBack)();
- }
- }
-
- /* Read and play on */
- ReadBuffer();
- PlayBuffer();
-
- /* Release protection against SCSI driver */
- Permit();
- }
-
-
- /*******************************************************************************/
-
- /* Execute a SCSI command (synchronous or asynchronous) */
-
- UBYTE* SenseKeys[]=
- {
- "NO SENSE",
- "RECOVERED ERROR",
- "NOT READY",
- "MEDIUM ERROR",
- "HARDWARE ERRROR",
- "ILLEGAL REQUEST",
- "UNIT ATTENTION",
- "DATA PROTECT",
- "BLANK CHECK",
- "VENDOR-SPECIFIC",
- "COPY ABORTED",
- "ABORTED COMMAND",
- "EQUAL",
- "VOLUME OVERFLOW",
- "MISCOMPARE",
- "RESERVED"
- };
-
- struct ErrorDefinition
- {
- UWORD ErrorCode;
- UBYTE *ErrorName;
- };
-
-
- struct ErrorDefinition ErrorTable[]=
- {
- 0x1300,"ADDRESS MARK NOT FOUND FOR DATA FIELD",
- 0x1200,"ADDRESS MARK NOT FOUND FOR ID FIELD",
- 0x0011,"AUDIO PLAY OPERATION IN PROGRESS",
- 0x0012,"AUDIO PLAY OPERATION PAUSED",
- 0x0014,"AUDIO PLAY OPERATION STOPPED DUE TO ERROR",
- 0x0013,"AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED",
- 0x0004,"BEGINNING-OF-PARTITION/MEDIUM DETECTED",
- 0x1404,"BLOCK SEQUENCE ERROR",
- 0x3002,"CANNOT READ MEDIUM - INCOMPATIBLE FORMAT",
- 0x3001,"CANNOT READ MEDIUM - UNKNOWN FORMAT",
- 0x5200,"CARTRIDGE FAULT",
- 0x3F02,"CHANGED OPERATING DEFINITION",
- 0x1106,"CIRC UNRECOVERED ERROR",
- 0x3003,"CLEANING CARTRIDGE INSTALLED",
- 0x4A00,"COMMAND PHASE ERROR",
- 0x2C00,"COMMAND SEQUENCE ERROR",
- 0x2F00,"COMMANDS CLEARED BY ANOTHER INITIATOR",
- 0x2B00,"COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT",
- 0x4100,"DATA PATH FAILURE",
- 0x4B00,"DATA PHASE ERROR",
- 0x1107,"DATA RESYCHRONIZATION ERROR",
- 0x1600,"DATA SYNCHRONIZATION MARK ERROR",
- 0x1900,"DEFECT LIST ERROR",
- 0x1903,"DEFECT LIST ERROR IN GROWN LIST",
- 0x1902,"DEFECT LIST ERROR IN PRIMARY LIST",
- 0x1901,"DEFECT LIST NOT AVAILABLE",
- 0x1C00,"DEFECT LIST NOT FOUND",
- 0x3201,"DEFECT LIST UPDATE FAILURE",
- 0x6300,"END OF USER AREA ENCOUNTERED ON THIS TRACK",
- 0x0005,"END-OF-DATA DETECTED",
- 0x1403,"END-OF-DATA NOT FOUND",
- 0x0002,"END-OF-PARTITION/MEDIUM DETECTED",
- 0x5100,"ERASE FAILURE",
- 0x0A00,"ERROR LOG OVERFLOW",
- 0x1102,"ERROR TOO LONG TO CORRECT",
- 0x0302,"EXCESSIVE WRITE ERRORS",
- 0x3B07,"FAILED TO SENSE BOTTOM-OF-FORM",
- 0x3B06,"FAILED TO SENSE TOP-OF-FORM",
- 0x0001,"FILEMARK DETECTED",
- 0x1402,"FILEMARK OR SETMARK NOT FOUND",
- 0x0902,"FOCUS SERVO FAILURE",
- 0x3101,"FORMAT COMMAND FAILED",
- 0x5800,"GENERATION DOES NOT EXIST",
- 0x1C02,"GROWN DEFECT LIST NOT FOUND",
- 0x0006,"I/O PROCESS TERMINATED",
- 0x1000,"ID CRC OR ECC ERROR",
- 0x2200,"ILLEGAL FUNCTION",
- 0x6400,"ILLEGAL MODE FOR THIS TRACK",
- 0x2801,"IMPORT OR EXPORT ELEMENT ACCESSED",
- 0x3000,"INCOMPATIBLE MEDIUM INSTALLED",
- 0x1108,"INCOMPLETE BLOCK READ",
- 0x4800,"INITIATOR DETECTED ERROR MESSAGE RECEIVED",
- 0x3F03,"INQUIRY DATA HAS CHANGED",
- 0x4400,"INTERNAL TARGET FAILURE",
- 0x3D00,"INVALID BITS IN IDENTIFY MESSAGE",
- 0x2C02,"INVALID COMBINATION OF WINDOWS SPECIFIED",
- 0x2000,"INVALID COMMAND OPERATION CODE",
- 0x2101,"INVALID ELEMENT ADDRESS",
- 0x2400,"INVALID FIELD IN CDB",
- 0x2600,"INVALID FIELD IN PARAMETER LIST",
- 0x4900,"INVALID MESSAGE ERROR",
- 0x1105,"L-EC UNCORRECTABLE ERROR",
- 0x6000,"LAMP FAILURE",
- 0x5B02,"LOG COUNTER AT MAXIMUM",
- 0x5B00,"LOG EXCEPTION",
- 0x5B03,"LOG LIST CODES EXHAUSTED",
- 0x2A02,"LOG PARAMETERS CHANGED",
- 0x2100,"LOGICAL BLOCK ADDRESS OUT OF RANGE",
- 0x0800,"LOGICAL UNIT COMMUNICATION FAILURE",
- 0x0802,"LOGICAL UNIT COMMUNICATION PARITY ERROR",
- 0x0801,"LOGICAL UNIT COMMUNICATION TIME-OUT",
- 0x0500,"LOGICAL UNIT DOES NOT RESPOND TO SELECTION",
- 0x4C00,"LOGICAL UNIT FAILED SELF-CONFIGURATION",
- 0x3E00,"LOGICAL UNIT HAS NOT SELF-CONFIGURED YET",
- 0x0401,"LOGICAL UNIT IS IN PROCESS OF BECOMING READY",
- 0x0400,"LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE",
- 0x0404,"LOGICAL UNIT NOT READY, FORMAT IN PROGRESS",
- 0x0402,"LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED",
- 0x0403,"LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED",
- 0x2500,"LOGICAL UNIT NOT SUPPORTED",
- 0x1501,"MECHANICAL POSITIONING ERROR",
- 0x5300,"MEDIA LOAD OR EJECT FAILED",
- 0x3B0D,"MEDIUM DESTINATION ELEMENT FULL",
- 0x3100,"MEDIUM FORMAT CORRUPTED",
- 0x3A00,"MEDIUM NOT PRESENT",
- 0x5302,"MEDIUM REMOVAL PREVENTED",
- 0x3B0E,"MEDIUM SOURCE ELEMENT EMPTY",
- 0x4300,"MESSAGE ERROR",
- 0x3F01,"MICROCODE HAS BEEN CHANGED",
- 0x1D00,"MISCOMPARE DURING VERIFY OPERATION",
- 0x110A,"MISCORRECTED ERROR",
- 0x2A01,"MODE PARAMETERS CHANGED",
- 0x0700,"MULTIPLE PERIPHERAL DEVICES SELECTED",
- 0x1103,"MULTIPLE READ ERRORS",
- 0x0000,"NO ADDITIONAL SENSE INFORMATION",
- 0x0015,"NO CURRENT AUDIO STATUS TO RETURN",
- 0x3200,"NO DEFECT SPARE LOCATION AVAILABLE",
- 0x1109,"NO GAP FOUND",
- 0x0100,"NO INDEX/SECTOR SIGNAL",
- 0x0600,"NO REFERENCE POSITION FOUND",
- 0x0200,"NO SEEK COMPLETE",
- 0x0301,"NO WRITE CURRENT",
- 0x2800,"NOT READY TO READY TRANSITION (MEDIUM MAY HAVE CHANGED)",
- 0x5A01,"OPERATOR MEDIUM REMOVAL REQUEST",
- 0x5A00,"OPERATOR REQUEST OR STATE CHANGE INPUT (UNSPECIFIED)",
- 0x5A03,"OPERATOR SELECTED WRITE PERMIT",
- 0x5A02,"OPERATOR SELECTED WRITE PROTECT",
- 0x6102,"OUT OF FOCUS",
- 0x4E00,"OVERLAPPED COMMANDS ATTEMPTED",
- 0x2D00,"OVERWRITE ERROR ON UPDATE IN PLACE",
- 0x3B05,"PAPER JAM",
- 0x1A00,"PARAMETER LIST LENGTH ERROR",
- 0x2601,"PARAMETER NOT SUPPORTED",
- 0x2602,"PARAMETER VALUE INVALID",
- 0x2A00,"PARAMETERS CHANGED",
- 0x0300,"PERIPHERAL DEVICE WRITE FAULT",
- 0x5002,"POSITION ERROR RELATED TO TIMING",
- 0x3B0C,"POSITION PAST BEGINNING OF MEDIUM",
- 0x3B0B,"POSITION PAST END OF MEDIUM",
- 0x1502,"POSITIONING ERROR DETECTED BY READ OF MEDIUM",
- 0x2900,"POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",
- 0x4200,"POWER-ON OR SELF-TEST FAILURE",
- 0x1C01,"PRIMARY DEFECT LIST NOT FOUND",
- 0x4000,"RAM FAILURE",
- 0x1500,"RANDOM POSITIONING ERROR",
- 0x3B0A,"READ PAST BEGINNING OF MEDIUM",
- 0x3B09,"READ PAST END OF MEDIUM",
- 0x1101,"READ RETRIES EXHAUSTED",
- 0x1401,"RECORD NOT FOUND",
- 0x1400,"RECORDED ENTITY NOT FOUND",
- 0x1802,"RECOVERED DATA - DATA AUTO-REALLOCATED",
- 0x1805,"RECOVERED DATA - RECOMMEND REASSIGNMENT",
- 0x1705,"RECOVERED DATA USING PREVIOUS SECTOR ID",
- 0x1803,"RECOVERED DATA WITH CIRC",
- 0x1801,"RECOVERED DATA WITH ERROR CORRECTION AND RETRIES APPLIED",
- 0x1800,"RECOVERED DATA WITH ERROR CORRECTION APPLIED",
- 0x1804,"RECOVERED DATA WITH LEC",
- 0x1703,"RECOVERED DATA WITH NEGATIVE HEAD OFFSET",
- 0x1700,"RECOVERED DATA WITH NO ERROR CORRECTION APPLIED",
- 0x1702,"RECOVERED DATA WITH POSITIVE HEAD OFFSET",
- 0x1701,"RECOVERED DATA WITH RETRIES",
- 0x1704,"RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED",
- 0x1706,"RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED",
- 0x1707,"RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT",
- 0x1E00,"RECOVERED ID WITH ECC CORRECTION",
- 0x3B08,"REPOSITION ERROR",
- 0x3600,"RIBBON, INK, OR TONER FAILURE",
- 0x3700,"ROUNDED PARAMETER",
- 0x5C00,"RPL STATUS CHANGE",
- 0x3900,"SAVING PARAMETERS NOT SUPPORTED",
- 0x6200,"SCAN HEAD POSITIONING ERROR",
- 0x4700,"SCSI PARITY ERROR",
- 0x5400,"SCSI TO HOST SYSTEM INTERFACE FAILURE",
- 0x4500,"SELECT OR RESELECT FAILURE",
- 0x3B00,"SEQUENTIAL POSITIONING ERROR",
- 0x0003,"SETMARK DETECTED",
- 0x3B04,"SLEW FAILURE",
- 0x0903,"SPINDLE SERVO FAILURE",
- 0x5C02,"SPINDLES NOT SYNCHRONIZED",
- 0x5C01,"SPINDLES SYNCHRONIZED",
- 0x1B00,"SYNCHRONOUS DATA TRANSFER ERROR",
- 0x5500,"SYSTEM RESOURCE FAILURE",
- 0x3300,"TAPE LENGTH ERROR",
- 0x3B03,"TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY",
- 0x3B01,"TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM",
- 0x3B02,"TAPE POSITION ERROR AT END-OF-MEDIUM",
- 0x3F00,"TARGET OPERATING CONDITIONS HAVE CHANGED",
- 0x5B01,"THRESHOLD CONDITION MET",
- 0x2603,"THRESHOLD PARAMETERS NOT SUPPORTED",
- 0x2C01,"TOO MANY WINDOWS SPECIFIED",
- 0x0900,"TRACK FOLLOWING ERROR",
- 0x0901,"TRACKING SERVO FAILURE",
- 0x6101,"UNABLE TO ACQUIRE VIDEO",
- 0x5700,"UNABLE TO RECOVER TABLE-OF-CONTENTS",
- 0x5301,"UNLOAD TAPE FAILURE",
- 0x1100,"UNRECOVERED READ ERROR",
- 0x1104,"UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED",
- 0x110B,"UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT",
- 0x110C,"UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA",
- 0x4600,"UNSUCCESSFUL SOFT RESET",
- 0x5900,"UPDATED BLOCK READ",
- 0x6100,"VIDEO ACQUISITION ERROR",
- 0x5000,"WRITE APPEND ERROR",
- 0x5001,"WRITE APPEND POSITION ERROR",
- 0x0C00,"WRITE ERROR",
- 0x0C02,"WRITE ERROR - AUTO REALLOCATION FAILED",
- 0x0C01,"WRITE ERROR RECOVERED WITH AUTO REALLOCATION",
- 0x2700,"WRITE PROTECTED",
- 0xFFFF,"UNKNOWN ERROR CODE"
- };
-
-
- ULONG DoSCSI(struct IOStdReq *IORequest, APTR Command, ULONG CommandLength, APTR Buffer, ULONG Length, ULONG Flags, BOOL Asynchronous, UBYTE *ActivityName)
- {
- struct SCSICmd *Cmd=(struct SCSICmd*)IORequest->io_Data;
-
- /* loop forever */
- for (;;)
- {
- Cmd->scsi_Command=Command;
- Cmd->scsi_CmdLength=CommandLength;
- Cmd->scsi_Data=Buffer;
- Cmd->scsi_Length=Length;
- Cmd->scsi_Flags=Flags;
- Cmd->scsi_Actual=
- Cmd->scsi_CmdActual=
- Cmd->scsi_SenseActual=0;
-
- if (Cmd->scsi_SenseData)
- {
- Cmd->scsi_Flags |= SCSIF_AUTOSENSE;
- }
-
- IORequest->io_Flags=0;
- IORequest->io_Length=sizeof(struct SCSICmd);
- IORequest->io_Command=HD_SCSICMD;
-
- if (Asynchronous)
- {
- BeginIO(IORequest);
- break;
- }
- else
- {
- DoIO(IORequest);
-
- if (Cmd->scsi_SenseActual)
- {
- struct EasyStruct Req={ sizeof (struct EasyStruct),
- 0,
- "SCSI error",
- "SCSI unit reports error while %s\n%s: %s",
- "Retry|Cancel"};
-
- struct SenseData *SD;
- if (SD=(struct SenseData*)Cmd->scsi_SenseData)
- {
- BOOL OpenIntui=FALSE;
- UBYTE *KeyName=SenseKeys[SD->sensekey&0xf];
- UBYTE *AddName="NO ADDITIONAL ERROR CODE";
-
- if (SD->addlength>=6)
- {
- struct ErrorDefinition *ED;
- for(ED=ErrorTable;ED->ErrorCode!=0xffff;ED++)
- {
- if (ED->ErrorCode==SD->additionalsense) break;
- }
- AddName=ED->ErrorName;
- }
-
- if (!IntuitionBase)
- {
- IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",37);
- OpenIntui=TRUE;
- }
-
- if (IntuitionBase)
- {
- if (!EasyRequest(NULL, &Req, NULL, ActivityName, KeyName, AddName))
- {
- break;
- }
- }
-
- if (IntuitionBase && OpenIntui)
- {
- CloseLibrary((struct Library*)IntuitionBase);
- IntuitionBase=NULL;
- }
- }
- }
- else break;
- }
- }
- return(Cmd->scsi_Actual);
- }
-
-
- /*******************************************************************************/
-
- /* Show a message to the user */
-
- void __stdargs Message(UBYTE *Msg,...)
- {
- va_list Arg;
- struct EasyStruct Req={sizeof(struct EasyStruct),0,"CDPlayer message",0,"Okay"};
- Req.es_TextFormat=Msg;
- va_start(Arg,Msg);
-
- if (IntuitionBase)
- {
- EasyRequestArgs(NULL,&Req,0,Arg);
- }
- else
- {
- VPrintf(Msg,Arg);
- Printf("\n");
- }
-
- va_end(Arg);
- }
-