home *** CD-ROM | disk | FTP | other *** search
- // ___ ___
- // _/ /_______\ \_ ___ ___ __ _ _ __ ___ ___
- //__// / _______ \ \\___/ \___
- //_/ | ' \__ __/ ` | \_/ © Copyright 1998, Christopher Page \__
- // \ | | | |__ | | / \ All Rights Reserved /
- // >| . | _/ . |< >--- --- -- - - -- --- ---<
- // / \ \ | | / / \ / This file may not be distributed, reproduced or \
- // \ \ \_/ \_/ / / \ altered, in full or in part, without written /
- // \ \ / / \ permission from Christopher Page. Legal /
- // //\ \_________/ /\\ //\ action will be taken in cases where /
- //¯ ¯¯\ _______ /¯¯ ¯ ¯¯\ this notice is not obeyed. /¯¯¯¯¯
- //¯¯¯¯¯\_/ \_/¯¯¯¯¯¯¯¯¯\ ___________________________________ /¯¯¯¯¯¯
- // \_/ \_/
- //
- // Description:
- //
- // CD playback functions
- //
- // Functions:
- //
- // struct TWFCDData * TWFCD_Setup(REG(a0) STRPTR DeviceName, REG(d0) UBYTE UnitNum)
- // ULONG TWFCD_Shutdown(REG(a0) struct TWFCDData *tcs_OldData)
- // ULONG TWFCD_ReadTOC(REG(a0) struct TWFCDData *tcrt_CDData)
- // ULONG TWFCD_PlayTracks(REG(a0) struct TWFCDData *tcpt_CDData, REG(a1) struct TagItem *pt_Tags)
- // ULONG TWFCD_StopPlay(REG(a0) struct TWFCDData *tcsp_CDData)
- // ULONG TWFCD_PausePlay(REG(a0) struct TWFCDData *tcpp_CDData)
- // ULONG TWFCD_MotorControl(REG(a0) struct TWFCDData *tcet_CDData, REG(d0) UBYTE newStatus)
- // ULONG TWFCD_ReadSubChannel(REG(a0) struct TWFCDData *tcrs_CDData)
- // static ULONG TWFCD_DoSCSICmd(struct TWFCDData *tcdc_CDData, UBYTE *buffer, int bufferSize, UBYTE *cmd, int cmdSize, UBYTE flags)
- //
- // Detail:
- //
- // This code provides a simple method to query the contents of a CD and start, stop
- // and pause playback of audio tracks on that CD. This is still work in progress and
- // likely to have problems on some non-standard/ older CD-ROM models.
- //
- //
- // Version:
- //
- // $VER: twfsound_cd.c 3.18 (17/10/1999)
- //
- // Fold Markers:
- //
- // Start: /*GFS*/
- // End: /*GFE*/
- //
- // Coded by and received from "The World Foundry",
- // (chris@worldfoundry.demon.co.uk)
- // This code is *not* under GPL, but it can be used for Freeware and
- // commercial projects. It is allowed to include the source-code, but
- // it is not required (Unless the game in question - like Quake -
- // requires to release the source). The release of this code inside
- // a GPL project like Quake does not put other projects which use
- // this code GPL, as this CD Audio Replay Code is not GPL, despite the
- // fact that the source code is allowed to be included.
- // Despite being freeware, source code modifications in this source
- // require the agreement of TWF. This especially includes also
- // recompiles to different Kernels.
-
- /*
- Portability
- ===========
-
- This file includes support for WarpUP and 68k. In case of
- PowerUP the AllocVecPPC/FreeVecPPC calls would be needed
- to be replaced by alternative functions. I am not sure
- if a modification to compile this with PowerUP would be
- agreed by the original authors. It is possible that this
- might be a problem. But if someone wants to compile Quake
- for PowerUP - i personally doubt that this is worth the
- effort for anyone - he has to check this out with TWF,
- or look for a different CD Audio Replay Solution. I did
- not ask TWF about this, as I personally don't care if a
- PowerUP version will be done or not. Some includes would
- need to be changed for different compilers, like usual.
-
- Steffen Haeuser (MagicSN@Birdland.es.bawue.de)
- */
-
- /*
- * Additional changes, as required for our Quake port, and
- * PowerUp support by Frank Wille <frank@phoenix.owl.de> (phx)
- */
-
- #pragma amiga-align
- #include <exec/exec.h>
- #include <devices/trackdisk.h>
- #include "twfsound_cd.h"
- #ifdef __PPC__
- #ifdef WOS
- #include <clib/powerpc_protos.h>
- #else /* PowerUp */
- #include <powerup/gcclib/powerup_protos.h>
- #endif
- #endif
- #pragma default-align
- #include <stdio.h>
-
- #if 0 /* initialized in sys_amiga.c (phx) */
- struct Library *UtilityBase;
- #endif
-
- // Non-standard, and a bit of a cheat, but it makes the code easier to read
- struct TOCData
- {
- UBYTE Empty1; // Padding
- UBYTE Flags ;
- UBYTE Track ;
- UBYTE Empty2;
- ULONG Addr ;
- };
-
- struct SubQData
- {
- UBYTE Reserved ; // Header: bytes 0 to 3
- UBYTE AudioStatus;
- UWORD DataLength ;
- UBYTE Formatcode ; // Data: byte 4
- UBYTE AdrControl ; // Byte 5
- UBYTE TrackNum ; // Byte 6
- UBYTE IndexNum ; // Byte 7
- ULONG AbsoluteAdr; // Bytes 8, 9, 10, 11
- ULONG RelativeAdr; // Bytes 12, 13, 14, 15
- };
-
- /* (phx) @@@? use -DNDEBUG instead! */
- /* #define kprintf */
-
- static ULONG TWFCD_DoSCSICmd(struct TWFCDData *, UBYTE *, int , UBYTE *, int, UBYTE);
-
- /* ULONG TWFCD_Setup(STRPTR, UBYTE) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
- /* This routine creates the message port and IO structure needed by the */
- /* device, then it attepmts to open the device.. nothig really groundbreaking*/
- /* in here you know... */
-
- /*GFS*/ struct TWFCDData * TWFCD_Setup(STRPTR DeviceName, UBYTE UnitNum)
- {
- struct TWFCDData *NewData = NULL;
- BYTE DeviceCode = 0;
-
-
- #if 0 /* this should be done in sys_amiga.c (phx) */
- UtilityBase=(struct Library *)OpenLibrary("utility.library",0);
- #endif
-
- // create the table...
- #ifdef __PPC__
- #ifdef WOS
- if(!(NewData = AllocVecPPC(sizeof(struct TWFCDData), MEMF_ANY|MEMF_CLEAR,0))) return(NULL);
- (NewData->TWFCD_Cmd).cdc_SCSIData=AllocVecPPC(CDBUFFER_SIZE,MEMF_CHIP|MEMF_CLEAR,0);
- #else /* PowerUp */
- if(!(NewData = PPCAllocVec(sizeof(struct TWFCDData), MEMF_ANY|MEMF_CLEAR))) return(NULL);
- (NewData->TWFCD_Cmd).cdc_SCSIData=PPCAllocVec(CDBUFFER_SIZE,MEMF_CHIP|MEMF_CLEAR);
- #endif
- #else
- if(!(NewData = AllocVec(sizeof(struct TWFCDData), MEMF_ANY|MEMF_CLEAR))) return(NULL);
- (NewData->TWFCD_Cmd).cdc_SCSIData=AllocVec(CDBUFFER_SIZE,MEMF_CHIP|MEMF_CLEAR);
- #endif
-
- if (!((NewData->TWFCD_Cmd).cdc_SCSIData))
- {
- #ifdef __PPC__
- #ifdef WOS
- FreeVecPPC(NewData);
- #else /* PowerUp */
- PPCFreeVec(NewData);
- #endif
- #else
- FreeVec(NewData);
- #endif
- return 0;
- }
- #ifdef __PPC__
- #ifdef WOS
- (NewData->TWFCD_Cmd).cdc_SCSISense=AllocVecPPC(CDSENSE_SIZE,MEMF_CHIP|MEMF_CLEAR,0);
- if (!((NewData->TWFCD_Cmd).cdc_SCSISense))
- {
- FreeVecPPC((NewData->TWFCD_Cmd).cdc_SCSIData);
- FreeVecPPC(NewData);
- return 0;
- }
- (NewData->TWFCD_Cmd).cdc_TOCBuffer=AllocVecPPC(CDTOC_SIZE,MEMF_CHIP|MEMF_CLEAR,0);
- if (!((NewData->TWFCD_Cmd).cdc_TOCBuffer))
- {
- FreeVecPPC((NewData->TWFCD_Cmd).cdc_SCSIData);
- FreeVecPPC((NewData->TWFCD_Cmd).cdc_SCSISense);
- FreeVecPPC(NewData);
- }
- #else /* PowerUp */
- (NewData->TWFCD_Cmd).cdc_SCSISense=PPCAllocVec(CDSENSE_SIZE,MEMF_CHIP|MEMF_CLEAR);
- if (!((NewData->TWFCD_Cmd).cdc_SCSISense))
- {
- PPCFreeVec((NewData->TWFCD_Cmd).cdc_SCSIData);
- PPCFreeVec(NewData);
- return 0;
- }
- (NewData->TWFCD_Cmd).cdc_TOCBuffer=PPCAllocVec(CDTOC_SIZE,MEMF_CHIP|MEMF_CLEAR);
- if (!((NewData->TWFCD_Cmd).cdc_TOCBuffer))
- {
- PPCFreeVec((NewData->TWFCD_Cmd).cdc_SCSIData);
- PPCFreeVec((NewData->TWFCD_Cmd).cdc_SCSISense);
- PPCFreeVec(NewData);
- }
- #endif
- #else
- (NewData->TWFCD_Cmd).cdc_SCSISense=AllocVec(CDSENSE_SIZE,MEMF_CHIP|MEMF_CLEAR);
- if (!((NewData->TWFCD_Cmd).cdc_SCSISense))
- {
- FreeVec((NewData->TWFCD_Cmd).cdc_SCSIData);
- FreeVec(NewData);
- return 0;
- }
- (NewData->TWFCD_Cmd).cdc_TOCBuffer=AllocVec(CDTOC_SIZE,MEMF_CHIP|MEMF_CLEAR);
- if (!((NewData->TWFCD_Cmd).cdc_TOCBuffer))
- {
- FreeVec((NewData->TWFCD_Cmd).cdc_SCSIData);
- FreeVec((NewData->TWFCD_Cmd).cdc_SCSISense);
- FreeVec(NewData);
- }
- #endif
-
- // Create the reply MsgPort for the device
- if(!(NewData -> TWFCD_Cmd.cdc_MsgPort = (struct MsgPort *)CreateMsgPort())) return(NULL);
-
- // Create our IORequest, to send Play IO messages to the CD device
- NewData -> TWFCD_Cmd.cdc_IOStdReq = (struct IOStdReq *)CreateIORequest(NewData -> TWFCD_Cmd.cdc_MsgPort, sizeof(struct IOStdReq));
- if(NewData -> TWFCD_Cmd.cdc_IOStdReq == NULL) return (NULL);
-
- // Open the CD device for the Play commands
- DeviceCode = OpenDevice(DeviceName, UnitNum, (struct IORequest *)NewData -> TWFCD_Cmd.cdc_IOStdReq, 0);
- if(DeviceCode != 0) return(NULL);
-
- ((NewData->TWFCD_Cmd).cdc_IOStdReq)->io_Command = CMD_START;
- DoIO((struct IORequest *)((NewData->TWFCD_Cmd).cdc_IOStdReq));
-
- // Device is now open, CD play available.
- return(NewData);
- } /*GFE*/
-
-
- /* ULONG TWFCD_Shutdown(TWFCDData *) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
- /* Call this to close the CD playback device, IO struct and message port */
- /* allocated by the TWFCD_Setup routine. */
-
- /*GFS*/ ULONG TWFCD_Shutdown(struct TWFCDData *tcs_OldData)
- {
- if(!tcs_OldData) return(TWFCD_FAIL);
-
- // Halt playback (so few people bother doing this.....)
- if(tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq) TWFCD_StopPlay(tcs_OldData);
-
- // Kill memory allocation
- if(tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq) CloseDevice ((struct IORequest*)tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq);
-
- if(tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq) {
- DeleteIORequest((struct IORequest*)tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq);
- tcs_OldData -> TWFCD_Cmd.cdc_IOStdReq = NULL;
- }
- if(tcs_OldData -> TWFCD_Cmd.cdc_MsgPort ) {
- DeleteMsgPort (tcs_OldData -> TWFCD_Cmd.cdc_MsgPort);
- tcs_OldData -> TWFCD_Cmd.cdc_MsgPort = NULL;
- }
-
- #ifdef __PPC__
- #ifdef WOS
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSIData) FreeVecPPC(tcs_OldData->TWFCD_Cmd.cdc_SCSIData);
- tcs_OldData->TWFCD_Cmd.cdc_SCSIData=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSISense) FreeVecPPC(tcs_OldData->TWFCD_Cmd.cdc_SCSISense);
- tcs_OldData->TWFCD_Cmd.cdc_SCSISense=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer) FreeVecPPC(tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer);
- tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer=0;
- if (tcs_OldData) FreeVecPPC(tcs_OldData);
- #else /* PowerUp */
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSIData) PPCFreeVec(tcs_OldData->TWFCD_Cmd.cdc_SCSIData);
- tcs_OldData->TWFCD_Cmd.cdc_SCSIData=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSISense) PPCFreeVec(tcs_OldData->TWFCD_Cmd.cdc_SCSISense);
- tcs_OldData->TWFCD_Cmd.cdc_SCSISense=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer) PPCFreeVec(tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer);
- tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer=0;
- if (tcs_OldData) PPCFreeVec(tcs_OldData);
- #endif
- #else
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSIData) FreeVec(tcs_OldData->TWFCD_Cmd.cdc_SCSIData);
- tcs_OldData->TWFCD_Cmd.cdc_SCSIData=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_SCSISense) FreeVec(tcs_OldData->TWFCD_Cmd.cdc_SCSISense);
- tcs_OldData->TWFCD_Cmd.cdc_SCSISense=0;
- if (tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer) FreeVec(tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer);
- tcs_OldData->TWFCD_Cmd.cdc_TOCBuffer=0;
- if (tcs_OldData) FreeVec(tcs_OldData);
- #endif
- tcs_OldData=0;
- return(TWFCD_OK);
- } /*GFE*/
-
-
- /* ULONG TWFCD_ReadTOC(void) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=- */
- /* This routine loads the table of contents off a CD and calculates a unique */
- /* disc identifier. out of range track identifiers are ignored (except by the*/
- /* ID generation) as most disks seem to have a mysterious track 170..?!! */
-
- /*GFS*/ ULONG TWFCD_ReadTOC(REG(a0) struct TWFCDData *tcrt_CDData)
- {
- ULONG ReturnCode = 0;
- BYTE Position = 0;
- ULONG Status = 0;
-
- ULONG TOCLength = 0;
- ULONG TOC170Adr = 0; // This records the address of track 170
- BOOL Enhanced = FALSE; // TRUE if a data track above track 1.
- struct TOCData *TOCPtr = NULL;
- struct TOCData *NextTOCPtr = NULL;
-
- ULONG LastStart = 0;
- ULONG ThisStart = 0;
-
- UBYTE ReadTOCCmd[10] = {
- SCSI_CMD_READTOC,
- 0,
- PAD,
- PAD,
- PAD,
- PAD,
- 0, // Starting track
- 0x03, 0x24, // Max. TOC data on current CDs is 0x324 bytes
- // or 100 track descriptors
- PAD
- };
-
- // Check for CD in drive
- tcrt_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Command = TD_CHANGESTATE;
- DoIO((struct IORequest *)tcrt_CDData -> TWFCD_Cmd.cdc_IOStdReq);
- if(tcrt_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Actual != 0)
- {
- tcrt_CDData -> TWFCD_Table.cda_FirstTrack = 0;
- tcrt_CDData -> TWFCD_Table.cda_LastTrack = 0;
- tcrt_CDData -> TWFCD_Table.cda_FirstAudio = 0;
- tcrt_CDData -> TWFCD_Table.cda_CDLength = 0;
- tcrt_CDData -> TWFCD_Table.cda_AudioLen = 0;
- tcrt_CDData -> TWFCD_Table.cda_DiskId[0] = '\0';
- tcrt_CDData -> TWFCD_Track.cds_AudioStatus = TWFCD_AUDIOSTATUS_INVALID;
- tcrt_CDData -> TWFCD_Track.cds_PlayTrack = 0;
- return(TWFCD_FAIL);
- }
-
- // Setup the direct SCSICmd
- Status = TWFCD_DoSCSICmd(tcrt_CDData,
- tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer, CDTOC_SIZE,
- ReadTOCCmd, sizeof(ReadTOCCmd),
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- if(Status != TWFCD_OK) {
- DEBUGLOG(kprintf("TWFCD_ReadTOC(): Status is not OK\n");)
- return(TWFCD_FAIL);
- }
-
- // Read the TOC in!
- ReturnCode = DoIO((struct IORequest *)tcrt_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- // Check the status of the direct cmd
- if(tcrt_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) {
-
- DEBUGLOG(kprintf("TWFCD_ReadTOC(): Command failed\n");)
-
- if(tcrt_CDData -> TWFCD_Table.cda_DiskId[0] != '\0') {
- tcrt_CDData -> TWFCD_Table.cda_FirstTrack = 0;
- tcrt_CDData -> TWFCD_Table.cda_LastTrack = 0;
- tcrt_CDData -> TWFCD_Table.cda_FirstAudio = 0;
- tcrt_CDData -> TWFCD_Table.cda_CDLength = 0;
- tcrt_CDData -> TWFCD_Table.cda_AudioLen = 0;
- tcrt_CDData -> TWFCD_Table.cda_DiskId[0] = '\0';
- tcrt_CDData -> TWFCD_Track.cds_AudioStatus = TWFCD_AUDIOSTATUS_INVALID;
- tcrt_CDData -> TWFCD_Track.cds_PlayTrack = 0;
- }
-
- return(TWFCD_FAIL);
- }
-
- // Read the length of the TOC - encoded in first word
- TOCLength = (tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[0] << 8) | tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[1];
-
- // Set track info...
- tcrt_CDData -> TWFCD_Table.cda_FirstTrack = tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[2];
- tcrt_CDData -> TWFCD_Table.cda_LastTrack = tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[3];
-
- tcrt_CDData -> TWFCD_Table.cda_CDLength = 0;
- tcrt_CDData -> TWFCD_Table.cda_AudioLen = 0;
-
- // Init [0] element to a safe state
- tcrt_CDData -> TWFCD_Table.cda_TrackData[0].cdt_Audio = FALSE;
-
- // Init first audio to TWFCD_NOAUDIO
- tcrt_CDData -> TWFCD_Table.cda_FirstAudio = TWFCD_NOAUDIO;
-
- // Account for First and last track numbers..
- if(TOCLength >= 2) TOCLength -= 2;
-
- for(TOCPtr = (struct TOCData *)&tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[4]; (UBYTE *)TOCPtr < (&tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[4] + TOCLength); TOCPtr = (struct TOCData *)((UBYTE *)TOCPtr + 8)) {
- NextTOCPtr = (struct TOCData *)((UBYTE *)TOCPtr + 8);
-
- // Check if track is audio or data
- if((TOCPtr -> Track >= tcrt_CDData -> TWFCD_Table.cda_FirstTrack) &&
- (TOCPtr -> Track <= tcrt_CDData -> TWFCD_Table.cda_LastTrack)) {
- if(TOCPtr -> Flags & 0x04) {
- // Data
- tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Audio = FALSE;
- if(TOCPtr -> Track > 1) Enhanced = TRUE;
- } else {
- // Audio track...
- tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Audio = TRUE;
- if(TOCPtr -> Track < tcrt_CDData -> TWFCD_Table.cda_FirstAudio) {
- tcrt_CDData -> TWFCD_Table.cda_FirstAudio = TOCPtr -> Track;
- }
- tcrt_CDData -> TWFCD_Table.cda_AudioLen += tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Length;
- }
- tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Address = TOCPtr -> Addr;
- tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Length = ((NextTOCPtr -> Addr - 1) - TOCPtr -> Addr); // / 75;
-
- tcrt_CDData -> TWFCD_Table.cda_CDLength += tcrt_CDData -> TWFCD_Table.cda_TrackData[TOCPtr -> Track].cdt_Length;
- }
-
- if(TOCPtr -> Track == 170) {
- TOC170Adr = (ULONG)TOCPtr -> Addr;
- }
-
- DEBUGLOG(kprintf("TWFCD_ReadTOC: TOCPtr -> track = %ld, TOCPtr -> addr = %06lX\n", (ULONG)TOCPtr -> Track, (ULONG)TOCPtr -> Addr);)
- }
-
- // Compose a MCDPlayer compatible CDID code.
- if(tcrt_CDData -> TWFCD_Table.cda_LastTrack > 3) {
- if(!Enhanced) {
- sprintf(tcrt_CDData -> TWFCD_Table.cda_DiskId, "ID%02lu%06lX%06lX", (ULONG)(tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[3] - tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[2]) + 1, (ULONG)tcrt_CDData -> TWFCD_Table.cda_TrackData[3].cdt_Address, TOC170Adr);
- } else {
- sprintf(tcrt_CDData -> TWFCD_Table.cda_DiskId, "ID%02lu%06lX%06lX", (ULONG)(tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[3] - tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[2]) + 1, (ULONG)tcrt_CDData -> TWFCD_Table.cda_TrackData[2].cdt_Address, TOC170Adr);
- }
- } else {
- sprintf(tcrt_CDData -> TWFCD_Table.cda_DiskId, "ID%02lu000000%06lX", (ULONG)(tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[3] - tcrt_CDData -> TWFCD_Cmd.cdc_TOCBuffer[2]) + 1, TOC170Adr);
- }
-
- DEBUGLOG(kprintf("TWFCD_ReadTOC: ID is %s\n", tcrt_CDData -> TWFCD_Table.cda_DiskId););
-
- tcrt_CDData -> TWFCD_Table.cda_GotTOC = TRUE;
-
- // Check the status of the command
- if (ReturnCode == 0) {
- return(TWFCD_OK);
- }
- else {
- return(TWFCD_FAIL);
- }
- }/*GFE*/
-
-
- /* ULONG TWFCD_PlayTracks(TWFCDData *, TagItem *) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
- /* This function starts the playback of one or more tracks on the CD referred*/
- /* to by the TWFCDData structure. It supports several playback command forms */
- /* specifically PLAYAUDIO10, PLAYAUDIO12 and PLAYAUDIO_TRACKINDEX. See the */
- /* tags for more details of this. This automatically calls TWFCD_ReadTOC if */
- /* the table of contents has not already been read. */
-
- /*GFS*/ ULONG TWFCD_PlayTracks(REG(a0) struct TWFCDData *tcpt_CDData, REG(a1) struct TagItem *pt_Tags)
- {
- struct TagItem *CountItem = NULL;
-
- LONG Start = 0;
- LONG tcpt_Length = 0;
-
- ULONG ReturnCode = 0;
- ULONG Status = 0;
-
- ULONG CmdLength = 10;
-
- UBYTE PlayCmd[12] =
- {
- SCSI_CMD_PLAYAUDIO_TRACKINDEX,
- PAD,
- PAD,
- PAD,
- 0, // Start track
- 1, // Index
- PAD,
- 0, // End track
- 1, // Index
- PAD,
- PAD,
- PAD
- };
-
- // Get the play mode
- PlayCmd[0] = (UBYTE)GetTagData(TWFCD_Track_PlayMode, SCSI_CMD_PLAYAUDIO12, pt_Tags);
-
- // is the TOC valid?
- if(!tcpt_CDData -> TWFCD_Table.cda_GotTOC) {
- ReturnCode = TWFCD_ReadTOC(tcpt_CDData);
- if(ReturnCode != TWFCD_OK) return(ReturnCode);
- }
-
- // Bomb if nothing to play.
- if(tcpt_CDData -> TWFCD_Table.cda_FirstAudio == TWFCD_NOAUDIO) return(TWFCD_NOAUDIO);
-
- // Start Track
- Start = GetTagData(TWFCD_Track_Start, tcpt_CDData -> TWFCD_Table.cda_FirstAudio, pt_Tags);
-
- // End Track
- if(CountItem = FindTagItem(TWFCD_Track_Count, pt_Tags)) {
- tcpt_Length = Start + (CountItem -> ti_Data - 1);
- } else {
- tcpt_Length = GetTagData(TWFCD_Track_End, tcpt_CDData -> TWFCD_Table.cda_LastTrack, pt_Tags);
- }
-
- // Make sure Start < End
- if(Start > tcpt_Length) {
- ReturnCode = Start;
- Start = tcpt_Length;
- tcpt_Length = ReturnCode;
- }
-
- // sort out the command...
- if(PlayCmd[0] == SCSI_CMD_PLAYAUDIO_TRACKINDEX) {
- PlayCmd[4] = Start;
- PlayCmd[7] = tcpt_Length;
- } else {
-
- // Common to PLAY10 and PLAY12
- Start = tcpt_CDData -> TWFCD_Table.cda_TrackData[Start].cdt_Address;
- PlayCmd[2] = (Start & 0xFF000000) >> 24;
- PlayCmd[3] = (Start & 0x00FF0000) >> 16;
- PlayCmd[4] = (Start & 0x0000FF00) >> 8;
- PlayCmd[5] = (Start & 0x000000FF);
-
- tcpt_Length = (tcpt_CDData -> TWFCD_Table.cda_TrackData[tcpt_Length].cdt_Address - Start) + tcpt_CDData -> TWFCD_Table.cda_TrackData[tcpt_Length].cdt_Length;
-
- if(PlayCmd[0] == SCSI_CMD_PLAYAUDIO12) {
- PlayCmd[6] = (tcpt_Length & 0xFF000000) >> 24;
- PlayCmd[7] = (tcpt_Length & 0x00FF0000) >> 16;
- PlayCmd[8] = (tcpt_Length & 0x0000FF00) >> 8;
- PlayCmd[9] = (tcpt_Length & 0x000000FF);
-
- CmdLength = 12;
- } else {
-
- // PLAY10
- PlayCmd[7] = (tcpt_Length & 0x0000FF00) >> 8;
- PlayCmd[8] = (tcpt_Length & 0x000000FF);
- }
- }
-
- // Setup the direct SCSICmd
- Status = TWFCD_DoSCSICmd(tcpt_CDData,
- tcpt_CDData -> TWFCD_Cmd.cdc_SCSIData, CDBUFFER_SIZE,
- PlayCmd, CmdLength,
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- if(Status != TWFCD_OK) return(TWFCD_FAIL);
-
- // Play the tracks - asynchronously (the play returns
- // right after a successful start)
- ReturnCode = DoIO((struct IORequest *) tcpt_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- // Check the status of the direct cmd
- if (tcpt_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) {
- return(TWFCD_FAIL);
- }
-
- // Check the status of the command
- if(ReturnCode == 0) {
- return(TWFCD_OK);
- } else {
- return(TWFCD_FAIL);
- }
-
- } /*GFE*/
-
-
- /* ULONG TWFCD_StopPlay(TWFCDData *) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
- /* This halts playback on the CD identified by the CD data structure. Note */
- /* that some CD players may not function correctly with this version, I am */
- /* researching other methods of playback halting. */
-
- /*GFS*/ ULONG TWFCD_StopPlay(REG(a0) struct TWFCDData *tcsp_CDData)
- {
- ULONG ReturnCode = 0;
- ULONG Status = 0;
-
- UBYTE StopCmd[6] =
- {
- SCSI_CMD_START_STOP_UNIT,
- PAD,
- PAD,
- PAD,
- PAD,
- PAD
- };
-
- DEBUGLOG(kprintf("TWFCD_StopPlay: in stop, compiling command\n");)
-
- // Check for CD in drive
- tcsp_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Command = TD_CHANGESTATE;
- DoIO((struct IORequest *)tcsp_CDData -> TWFCD_Cmd.cdc_IOStdReq);
- if(tcsp_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Actual != 0)
- return(TWFCD_OK);
-
- // Setup the direct SCSICmd
- Status = TWFCD_DoSCSICmd(tcsp_CDData,
- tcsp_CDData -> TWFCD_Cmd.cdc_SCSIData, CDBUFFER_SIZE,
- StopCmd, sizeof(StopCmd),
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- DEBUGLOG(kprintf("TWFCD_StopPlay: command ready\n");)
-
- if(Status != TWFCD_OK) return(TWFCD_FAIL);
-
- DEBUGLOG(kprintf("TWFCD_StopPlay: Sending command to device\n");)
-
- // Stop the CD (a play of length 0)
- ReturnCode = DoIO((struct IORequest *)tcsp_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- DEBUGLOG(kprintf("TWFCD_StopPlay: command sent, checking sense data\n");)
-
- // Check the status of the direct cmd
- if(tcsp_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) return(TWFCD_FAIL);
-
- DEBUGLOG(kprintf("TWFCD_StopPlay: sense check passed ok, returning\n");)
-
- // Check the status of the command
- if(ReturnCode == 0) {
- // not paused any more!
- tcsp_CDData -> TWFCD_Table.cda_Paused = FALSE;
- return(TWFCD_OK);
- } else {
- return(TWFCD_FAIL);
- }
- } /*GFE*/
-
-
- /* ULONG TWFCD_PausePlay(TWFCDData *) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
- /* As you'd expect, this pauses the playback on the specified device. Call */
- /* this again to resume the playback. */
-
- /*GFS*/ ULONG TWFCD_PausePlay(REG(a0) struct TWFCDData *tcpp_CDData)
- {
-
- ULONG ReturnCode = 0;
- ULONG Status = 0;
-
- UBYTE PauseCmd[10] = {
- SCSI_CMD_PAUSE_RESUME,
- PAD,
- PAD,
- PAD,
- PAD,
- PAD,
- PAD,
- PAD,
- 0,
- PAD
- };
-
- if(tcpp_CDData -> TWFCD_Table.cda_Paused) {
- DEBUGLOG(kprintf("TWFCD_PausePlay: CD is paused, resuming playback\n");)
- PauseCmd[8] = 1;
- tcpp_CDData -> TWFCD_Table.cda_Paused = FALSE;
- } else {
- DEBUGLOG(kprintf("TWFCD_PausePlay: CD is playing, pausing playback\n");)
- PauseCmd[8] = 0;
- tcpp_CDData -> TWFCD_Table.cda_Paused = TRUE;
- }
-
- // Setup the direct SCSICmd
- Status = TWFCD_DoSCSICmd(tcpp_CDData,
- tcpp_CDData -> TWFCD_Cmd.cdc_SCSIData, CDBUFFER_SIZE,
- PauseCmd, sizeof(PauseCmd),
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- if(Status != TWFCD_OK) return(TWFCD_FAIL);
-
- // Send the command...
- ReturnCode = DoIO((struct IORequest *)tcpp_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- // Check the status of the direct cmd
- if (tcpp_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) return(TWFCD_FAIL);
-
- DEBUGLOG(kprintf("TWFCD_PausePlay: return code is %d\n", ReturnCode);)
-
- // Check the status of the command
- if (ReturnCode == 0) {
- return(TWFCD_OK);
- } else {
- return(TWFCD_FAIL);
- }
- } /*GFE*/
-
-
- /* ULONG TWFCD_MotorControl(TWFCDData *, UBYTE) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
- /* This allows the motor and tray of the CD to be controlled. The value in */
- /* newStatus determines the operation you wish to perform, valid parameters */
- /* are: */
- /* */
- /* TWFCD_MOTOR_STOP - Turn off the drive (stops playback automagically) */
- /* TWFCD_MOTOR_START - Turns the motor on (but does nothing else..) */
- /* TWFCD_MOTOR_EJECT - Opens the CD tray if it is not already open. */
- /* TWFCD_MOTOR_LOAD - Closes the CD tray. */
-
- /*GFS*/ ULONG TWFCD_MotorControl(REG(a0) struct TWFCDData *tcmc_CDData, REG(d0) UBYTE newStatus)
- {
- ULONG returnCode = 0;
- ULONG status = 0;
- UBYTE ejectCmd[6] =
- {
- SCSI_CMD_START_STOP_UNIT,
- 0,
- PAD,
- PAD,
- 0, // Byte 5 = start/stop eject/insert
- PAD,
- };
-
- ejectCmd[4] = newStatus;
- status = TWFCD_DoSCSICmd(tcmc_CDData,
- tcmc_CDData -> TWFCD_Cmd.cdc_SCSIData, CDBUFFER_SIZE,
- &ejectCmd[0], sizeof(ejectCmd),
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- if(status != TWFCD_OK) {
- return(TWFCD_FAIL);
- }
-
- returnCode = DoIO((struct IORequest *) tcmc_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- // Check the status of the direct cmd
- if (tcmc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) {
-
- // Conceivably, someone may want to know why, so a debug
- // call should interpret the field
- return(TWFCD_FAIL);
- }
-
- // Check the status of the command
- if (returnCode == 0) {
- return(TWFCD_OK);
- }
- else {
- return(TWFCD_FAIL);
- }
- }/*GFE*/
-
-
- /* ULONG TWFCD_ReadSubChannel(TWFCDData *) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
- /* This reads the sub-Q channel data from the specified CD. It only reads in */
- /* format 1 (CD position information), although it could be extended to */
- /* support all format modes. */
-
- /*GFS*/ ULONG TWFCD_ReadSubChannel(REG(a0) struct TWFCDData *tcrs_CDData)
- {
- struct SubQData *chanData = NULL;
- ULONG returnCode = 0;
- ULONG status = 0;
-
- UBYTE readCmd[10] =
- {
- SCSI_CMD_READSUB_CHANNEL,
- 0,
- 0x40,
- 0x01,
- 0,
- 0,
- 0,
- 0,
- CDBUFFER_SIZE,
- 0,
- };
-
- // Setup the direct SCSICmd
- status = TWFCD_DoSCSICmd(tcrs_CDData,
- tcrs_CDData -> TWFCD_Cmd.cdc_SCSIData, CDBUFFER_SIZE,
- &readCmd[0], sizeof(readCmd),
- (SCSIF_READ | SCSIF_AUTOSENSE));
-
- if (status != TWFCD_OK) {
- return (TWFCD_FAIL);
- }
-
- returnCode = DoIO((struct IORequest *) tcrs_CDData -> TWFCD_Cmd.cdc_IOStdReq);
-
- // Check the status of the direct cmd
- if(tcrs_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual != 0) {
-
- // Conceivably, someone may want to know why, so a debug
- // call should interpret the field
- return(TWFCD_FAIL);
- }
-
- chanData = (struct SubQData *)tcrs_CDData -> TWFCD_Cmd.cdc_SCSIData;
-
- // Copy the settings...
- tcrs_CDData -> TWFCD_Track.cds_AudioStatus = chanData -> AudioStatus;
-
- // ... provided they are valid of course...
- if((chanData -> AudioStatus != TWFCD_AUDIOSTATUS_INVALID) &&
- (chanData -> AudioStatus != TWFCD_AUDIOSTATUS_NOSTATUS)){
-
- tcrs_CDData -> TWFCD_Track.cds_PlayTrack = chanData -> TrackNum ;
- tcrs_CDData -> TWFCD_Track.cds_RelAddress = chanData -> RelativeAdr;
-
- if(tcrs_CDData -> TWFCD_Table.cda_GotTOC) {
- tcrs_CDData -> TWFCD_Track.cds_RelRemain = tcrs_CDData -> TWFCD_Table.cda_TrackData[chanData -> TrackNum].cdt_Length - chanData -> RelativeAdr;
- } else {
- tcrs_CDData -> TWFCD_Track.cds_RelRemain = 0;
- }
-
- tcrs_CDData -> TWFCD_Track.cds_AbsAddress = chanData -> AbsoluteAdr;
- if(tcrs_CDData -> TWFCD_Table.cda_GotTOC) {
- tcrs_CDData -> TWFCD_Track.cds_AbsRemain = tcrs_CDData -> TWFCD_Table.cda_CDLength - chanData -> AbsoluteAdr;
- } else {
- tcrs_CDData -> TWFCD_Track.cds_AbsRemain = 0;
- }
- }
-
- // Check the status of the command
- if (returnCode == 0) {
- return(TWFCD_OK);
- }
- else {
- return(TWFCD_FAIL);
- }
- } /*GFE*/
-
-
- /* ULONG TWFCD_doSCSICmd(TWFCDData *, UBYTE *, int, UBYTE *, int, UBYTE) */
- /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
- /* This compiles the scsi-direct command ready for sending to the device via */
- /* DoIO(). It ensures the SCSI command structure in the TWFCDData struct is */
- /* set up correctly and the IORequest contains the command. */
-
- /*GFS*/ static ULONG TWFCD_DoSCSICmd(struct TWFCDData *tcdc_CDData, UBYTE *buffer, int bufferSize, UBYTE *cmd, int cmdSize, UBYTE flags)
- {
- // Set up the Play IOReq
- tcdc_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Command = HD_SCSICMD;
- tcdc_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Length = sizeof(struct SCSICmd);
- tcdc_CDData -> TWFCD_Cmd.cdc_IOStdReq->io_Data = (APTR)&tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd;
-
- // Setup the direct SCSICmd
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_Data = (APTR) buffer;
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_Length = bufferSize;
-
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseActual = 0;
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseData = tcdc_CDData -> TWFCD_Cmd.cdc_SCSISense;
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_SenseLength = CDSENSE_SIZE;
-
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_Command = (UBYTE *) cmd;
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_CmdLength = cmdSize;
- tcdc_CDData -> TWFCD_Cmd.cdc_SCSICmd.scsi_Flags = flags;
-
- return (TWFCD_OK);
- }/*GFE*/
-
-
-
-