Mercurial > sdl-ios-xcode
diff src/cdrom/macos/SDL_syscdrom.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | e8157fcb3114 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cdrom/macos/SDL_syscdrom.c Thu Apr 26 16:45:43 2001 +0000 @@ -0,0 +1,526 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* MacOS functions for system-level CD-ROM audio control */ + +#include <Devices.h> +#include <Files.h> +#include <LowMem.h> /* Use entry table macros, not functions in InterfaceLib */ + +#include "SDL_cdrom.h" +#include "SDL_syscdrom.h" +#include "SDL_syscdrom_c.h" + +/* Added by Matt Slot */ +#if !defined(LMGetUnitTableEntryCount) + #define LMGetUnitTableEntryCount() *(short *)0x01D2 +#endif + +/* The maximum number of CD-ROM drives we'll detect */ +#define MAX_DRIVES 26 + +/* A list of available CD-ROM drives */ +static long SDL_cdversion = 0; +static struct { + short dRefNum; + short driveNum; + long frames; + char name[256]; + Boolean hasAudio; + } SDL_cdlist[MAX_DRIVES]; +static StringPtr gDriverName = "\p.AppleCD"; + +/* The system-dependent CD control functions */ +static const char *SDL_SYS_CDName(int drive); +static int SDL_SYS_CDOpen(int drive); +static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); +static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); +static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); +static int SDL_SYS_CDPause(SDL_CD *cdrom); +static int SDL_SYS_CDResume(SDL_CD *cdrom); +static int SDL_SYS_CDStop(SDL_CD *cdrom); +static int SDL_SYS_CDEject(SDL_CD *cdrom); +static void SDL_SYS_CDClose(SDL_CD *cdrom); + +static short SDL_SYS_ShortToBCD(short value) +{ + return((value % 10) + (value / 10) * 0x10); /* Convert value to BCD */ +} + +static short SDL_SYS_BCDToShort(short value) +{ + return((value % 0x10) + (value / 0x10) * 10); /* Convert value from BCD */ +} + +int SDL_SYS_CDInit(void) +{ + SInt16 dRefNum = 0; + SInt16 first, last; + + SDL_numcds = 0; + + /* Check that the software is available */ + if (Gestalt(kGestaltAudioCDSelector, &SDL_cdversion) || + !SDL_cdversion) return(0); + + /* Fill in our driver capabilities */ + SDL_CDcaps.Name = SDL_SYS_CDName; + SDL_CDcaps.Open = SDL_SYS_CDOpen; + SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; + SDL_CDcaps.Status = SDL_SYS_CDStatus; + SDL_CDcaps.Play = SDL_SYS_CDPlay; + SDL_CDcaps.Pause = SDL_SYS_CDPause; + SDL_CDcaps.Resume = SDL_SYS_CDResume; + SDL_CDcaps.Stop = SDL_SYS_CDStop; + SDL_CDcaps.Eject = SDL_SYS_CDEject; + SDL_CDcaps.Close = SDL_SYS_CDClose; + + /* Walk the list, count each AudioCD driver, and save the refnums */ + first = -1; + last = 0 - LMGetUnitTableEntryCount(); + for(dRefNum = first; dRefNum >= last; dRefNum--) { + Str255 driverName; + StringPtr namePtr; + DCtlHandle deviceEntry; + + deviceEntry = GetDCtlEntry(dRefNum); + if (! deviceEntry) continue; + + /* Is this an .AppleCD ? */ + namePtr = (*deviceEntry)->dCtlFlags & (1L << dRAMBased) ? + ((StringPtr) ((DCtlPtr) deviceEntry)->dCtlDriver + 18) : + ((StringPtr) (*deviceEntry)->dCtlDriver + 18); + BlockMoveData(namePtr, driverName, namePtr[0]+1); + if (driverName[0] > gDriverName[0]) driverName[0] = gDriverName[0]; + if (! EqualString(driverName, gDriverName, false, false)) continue; + + /* Record the basic info for each drive */ + SDL_cdlist[SDL_numcds].dRefNum = dRefNum; + BlockMoveData(namePtr + 1, SDL_cdlist[SDL_numcds].name, namePtr[0]); + SDL_cdlist[SDL_numcds].name[namePtr[0]] = 0; + SDL_cdlist[SDL_numcds].hasAudio = false; + SDL_numcds++; + } + return(0); +} + +static const char *SDL_SYS_CDName(int drive) +{ + return(SDL_cdlist[drive].name); +} + +static int get_drivenum(int drive) +{ + QHdr *driveQ = GetDrvQHdr(); + DrvQEl *driveElem; + + /* Update the drive number */ + SDL_cdlist[drive].driveNum = 0; + if ( driveQ->qTail ) { + driveQ->qTail->qLink = 0; + } + for ( driveElem=(DrvQEl *)driveQ->qHead; driveElem; + driveElem = (DrvQEl *)driveElem->qLink ) { + if ( driveElem->dQRefNum == SDL_cdlist[drive].dRefNum ) { + SDL_cdlist[drive].driveNum = driveElem->dQDrive; + break; + } + } + return(SDL_cdlist[drive].driveNum); +} + +static int SDL_SYS_CDOpen(int drive) +{ + return(drive); +} + +static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) +{ + CDCntrlParam cdpb; + CDTrackData tracks[SDL_MAX_TRACKS]; + long i, leadout; + + /* Get the number of tracks on the CD by examining the TOC */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kReadTOC; + cdpb.csParam.words[0] = kGetTrackRange; + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + cdrom->numtracks = + SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - + SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1; + if ( cdrom->numtracks > SDL_MAX_TRACKS ) + cdrom->numtracks = SDL_MAX_TRACKS; + cdrom->status = CD_STOPPED; + cdrom->cur_track = 0; /* Apparently these are set elsewhere */ + cdrom->cur_frame = 0; /* Apparently these are set elsewhere */ + + + /* Get the lead out area of the CD by examining the TOC */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kReadTOC; + cdpb.csParam.words[0] = kGetLeadOutArea; + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + leadout = MSF_TO_FRAMES( + SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]), + SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]), + SDL_SYS_BCDToShort(cdpb.csParam.bytes[2])); + + /* Get an array of track locations by examining the TOC */ + memset(tracks, 0, sizeof(tracks)); + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kReadTOC; + cdpb.csParam.words[0] = kGetTrackEntries; /* Type of Query */ + * ((long *) (cdpb.csParam.words+1)) = (long) tracks; + cdpb.csParam.words[3] = cdrom->numtracks * sizeof(tracks[0]); + * ((char *) (cdpb.csParam.words+4)) = 1; /* First track */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + /* Read all the track TOC entries */ + SDL_cdlist[cdrom->id].hasAudio = false; + for ( i=0; i<cdrom->numtracks; ++i ) + { + cdrom->track[i].id = i+1; + if (tracks[i].entry.control & kDataTrackMask) + cdrom->track[i].type = SDL_DATA_TRACK; + else + { + cdrom->track[i].type = SDL_AUDIO_TRACK; + SDL_cdlist[SDL_numcds].hasAudio = true; + } + + cdrom->track[i].offset = MSF_TO_FRAMES( + SDL_SYS_BCDToShort(tracks[i].entry.min), + SDL_SYS_BCDToShort(tracks[i].entry.min), + SDL_SYS_BCDToShort(tracks[i].entry.frame)); + cdrom->track[i].length = MSF_TO_FRAMES( + SDL_SYS_BCDToShort(tracks[i+1].entry.min), + SDL_SYS_BCDToShort(tracks[i+1].entry.min), + SDL_SYS_BCDToShort(tracks[i+1].entry.frame)) - + cdrom->track[i].offset; + } + + /* Apparently SDL wants a fake last entry */ + cdrom->track[i].offset = leadout; + cdrom->track[i].length = 0; + + return(0); +} + +/* Get CD-ROM status */ +static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) +{ + CDCntrlParam cdpb; + CDstatus status = CD_ERROR; + Boolean spinning = false; + + if (position) *position = 0; + + /* Get the number of tracks on the CD by examining the TOC */ + if ( ! get_drivenum(cdrom->id) ) { + return(CD_TRAYEMPTY); + } + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kReadTOC; + cdpb.csParam.words[0] = kGetTrackRange; + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(CD_ERROR); + } + + cdrom->numtracks = + SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - + SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1; + if ( cdrom->numtracks > SDL_MAX_TRACKS ) + cdrom->numtracks = SDL_MAX_TRACKS; + cdrom->cur_track = 0; /* Apparently these are set elsewhere */ + cdrom->cur_frame = 0; /* Apparently these are set elsewhere */ + + + if (1 || SDL_cdlist[cdrom->id].hasAudio) { + /* Get the current playback status */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioStatus; + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + switch(cdpb.csParam.cd.status) { + case kStatusPlaying: + status = CD_PLAYING; + spinning = true; + break; + case kStatusPaused: + status = CD_PAUSED; + spinning = true; + break; + case kStatusMuted: + status = CD_PLAYING; /* What should I do here? */ + spinning = true; + break; + case kStatusDone: + status = CD_STOPPED; + spinning = true; + break; + case kStatusStopped: + status = CD_STOPPED; + spinning = false; + break; + case kStatusError: + default: + status = CD_ERROR; + spinning = false; + break; + } + + if (spinning && position) *position = MSF_TO_FRAMES( + SDL_SYS_BCDToShort(cdpb.csParam.cd.minute), + SDL_SYS_BCDToShort(cdpb.csParam.cd.second), + SDL_SYS_BCDToShort(cdpb.csParam.cd.frame)); + } + else + status = CD_ERROR; /* What should I do here? */ + + return(status); +} + +/* Start play */ +static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) +{ + CDCntrlParam cdpb; + + /* Pause the current audio playback to avoid audible artifacts */ + if ( SDL_SYS_CDPause(cdrom) < 0 ) { + return(-1); + } + + /* Specify the AudioCD playback mode */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kSetPlayMode; + cdpb.csParam.bytes[0] = false; /* Repeat? */ + cdpb.csParam.bytes[1] = kPlayModeSequential; /* Play mode */ + /* ¥¥¥ÊTreat as soft error, NEC Drive doesnt support this call ¥¥¥ */ + PBControlSync((ParmBlkPtr) &cdpb); + +#if 1 + /* Specify the end of audio playback */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioStop; + cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */ + *(long *) (cdpb.csParam.words + 1) = start+length-1; /* Search Address */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + /* Specify the start of audio playback, and start it */ + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioPlay; + cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */ + *(long *) (cdpb.csParam.words + 1) = start+1; /* Search Address */ + cdpb.csParam.words[3] = false; /* Stop address? */ + cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } +#else + /* Specify the end of audio playback */ + FRAMES_TO_MSF(start+length, &m, &s, &f); + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioStop; + cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */ + cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/ + cdpb.csParam.words[2] = /* Search Address (loword)*/ + SDL_SYS_ShortToBCD(cdrom->numtracks); + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + + /* Specify the start of audio playback, and start it */ + FRAMES_TO_MSF(start, &m, &s, &f); + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioPlay; + cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */ + cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/ + cdpb.csParam.words[2] = SDL_SYS_ShortToBCD(1); /* Search Address (loword)*/ + cdpb.csParam.words[3] = false; /* Stop address? */ + cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } +#endif + + return(0); +} + +/* Pause play */ +static int SDL_SYS_CDPause(SDL_CD *cdrom) +{ + CDCntrlParam cdpb; + + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioPause; + cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */ + cdpb.csParam.words[1] = 1; /* Pause/Continue Flag (loword) */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + return(0); +} + +/* Resume play */ +static int SDL_SYS_CDResume(SDL_CD *cdrom) +{ + CDCntrlParam cdpb; + + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioPause; + cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */ + cdpb.csParam.words[1] = 0; /* Pause/Continue Flag (loword) */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + return(0); +} + +/* Stop play */ +static int SDL_SYS_CDStop(SDL_CD *cdrom) +{ + CDCntrlParam cdpb; + + memset(&cdpb, 0, sizeof(cdpb)); + cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; + cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cdpb.csCode = kAudioStop; + cdpb.csParam.words[0] = 0; /* Position Mode */ + cdpb.csParam.words[1] = 0; /* Search Address (hiword) */ + cdpb.csParam.words[2] = 0; /* Search Address (loword) */ + if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + return(0); +} + +/* Eject the CD-ROM */ +static int SDL_SYS_CDEject(SDL_CD *cdrom) +{ + Boolean disk = false; + QHdr *driveQ = GetDrvQHdr(); + DrvQEl *driveElem; + HParamBlockRec hpb; + ParamBlockRec cpb; + + for ( driveElem = (DrvQEl *) driveQ->qHead; driveElem; driveElem = + (driveElem) ? ((DrvQEl *) driveElem->qLink) : + ((DrvQEl *) driveQ->qHead) ) { + if ( driveQ->qTail ) { + driveQ->qTail->qLink = 0; + } + if ( driveElem->dQRefNum != SDL_cdlist[cdrom->id].dRefNum ) { + continue; + } + + /* Does drive contain mounted volume? If not, skip */ + memset(&hpb, 0, sizeof(hpb)); + hpb.volumeParam.ioVRefNum = driveElem->dQDrive; + if ( PBHGetVInfoSync(&hpb) != noErr ) { + continue; + } + if ( (UnmountVol(0, driveElem->dQDrive) == noErr) && + (Eject(0, driveElem->dQDrive) == noErr) ) { + driveElem = 0; /* Clear pointer to reset our loop */ + disk = true; + } + } + + /* If no disk is present, just eject the tray */ + if (! disk) { + memset(&cpb, 0, sizeof(cpb)); + cpb.cntrlParam.ioVRefNum = 0; /* No Drive */ + cpb.cntrlParam.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; + cpb.cntrlParam.csCode = kEjectTheDisc; + if ( PBControlSync((ParmBlkPtr)&cpb) != noErr ) { + SDL_SetError("PBControlSync() failed"); + return(-1); + } + } + return(0); +} + +/* Close the CD-ROM handle */ +static void SDL_SYS_CDClose(SDL_CD *cdrom) +{ + return; +} + +void SDL_SYS_CDQuit(void) +{ + while(SDL_numcds--) + memset(SDL_cdlist + SDL_numcds, 0, sizeof(SDL_cdlist[0])); +} +