| /* |
| SDL - Simple DirectMedia Layer |
| Copyright (C) 1997-2012 Sam Lantinga |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 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 |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| Sam Lantinga |
| slouken@libsdl.org |
| */ |
| #include "SDL_config.h" |
| |
| #ifdef SDL_CDROM_OS2 |
| |
| /* Functions for system-level CD-ROM audio control */ |
| |
| #define INCL_MCIOS2 |
| #include <os2.h> |
| #include <os2me.h> |
| |
| #include "SDL_cdrom.h" |
| #include "../SDL_syscdrom.h" |
| |
| /* Size of MCI result buffer (in bytes) */ |
| #define MCI_CMDRETBUFSIZE 128 |
| |
| /* The maximum number of CD-ROM drives we'll detect */ |
| #define MAX_DRIVES 16 |
| |
| /* A list of available CD-ROM drives */ |
| static char *SDL_cdlist[MAX_DRIVES]; |
| //static dev_t SDL_cdmode[MAX_DRIVES]; |
| |
| /* 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); |
| |
| /* MCI Timing Functions */ |
| #define MCI_MMTIMEPERSECOND 3000 |
| #define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND) |
| |
| |
| /* Ready for MCI CDAudio Devices */ |
| int SDL_SYS_CDInit(void) |
| { |
| int i; /* generig counter */ |
| MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ |
| CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ |
| |
| /* 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; |
| |
| /* Get the number of CD ROMs in the System */ |
| /* Clean SysInfo structure */ |
| SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); |
| /* Prepare structure to Ask Numer of Audio CDs */ |
| msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ |
| msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ |
| msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ |
| if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
| SDL_numcds = atoi(SysInfoRet); |
| if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ |
| |
| /* Get and Add their system name to the SDL_cdlist */ |
| msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ |
| msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ |
| msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ |
| for (i=0; i<SDL_numcds; i++) |
| { |
| msp.ulNumber = i+1; |
| mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0); |
| SDL_cdlist[i] = SDL_strdup(SysInfoRet); |
| if ( SDL_cdlist[i] == NULL ) |
| { |
| SDL_OutOfMemory(); |
| return(-1); |
| } |
| } |
| return(0); |
| } |
| |
| /* Return CDAudio System Dependent Device Name - Ready for MCI*/ |
| static const char *SDL_SYS_CDName(int drive) |
| { |
| return(SDL_cdlist[drive]); |
| } |
| |
| /* Open CDAudio Device - Ready for MCI */ |
| static int SDL_SYS_CDOpen(int drive) |
| { |
| MCI_OPEN_PARMS mop; |
| MCI_SET_PARMS msp; |
| MCI_GENERIC_PARMS mgp; |
| |
| /* Open the device */ |
| mop.hwndCallback = (HWND)NULL; // None |
| mop.usDeviceID = (USHORT)NULL; // Will be returned. |
| mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device |
| if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
| /* Set time format */ |
| msp.hwndCallback = (HWND)NULL; // None |
| msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure |
| msp.ulSpeedFormat = (ULONG)NULL; // No change |
| msp.ulAudio = (ULONG)NULL; // No Channel |
| msp.ulLevel = (ULONG)NULL; // No Volume |
| msp.ulOver = (ULONG)NULL; // No Delay |
| msp.ulItem = (ULONG)NULL; // No item |
| msp.ulValue = (ULONG)NULL; // No value for item flag |
| if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID); |
| /* Error setting time format? - Close opened device */ |
| mgp.hwndCallback = (HWND)NULL; // None |
| mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0); |
| return(CD_ERROR); |
| } |
| |
| /* Get CD Table Of Contents - Ready for MCI */ |
| static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) |
| { |
| MCI_TOC_PARMS mtp; |
| MCI_STATUS_PARMS msp; |
| MCI_TOC_REC * mtr; |
| INT i; |
| |
| /* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */ |
| if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; |
| |
| /* Get Number of Tracks */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; |
| msp.ulValue = (ULONG)NULL; /* No additional information */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); |
| cdrom->numtracks = msp.ulReturn; |
| if ( cdrom->numtracks > SDL_MAX_TRACKS ) |
| { |
| cdrom->numtracks = SDL_MAX_TRACKS; |
| } |
| /* Alocate space for TOC data */ |
| mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); |
| if ( mtr == NULL ) |
| { |
| SDL_OutOfMemory(); |
| return(-1); |
| } |
| /* Get TOC from CD */ |
| mtp.pBuf = mtr; |
| mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS) |
| { |
| SDL_OutOfMemory(); |
| SDL_free(mtr); |
| return(CD_ERROR); |
| } |
| /* Fill SDL Tracks Structure */ |
| for (i=0; i<cdrom->numtracks; i++) |
| { |
| /* Set Track ID */ |
| cdrom->track[i].id = (mtr+i)->TrackNum; |
| /* Set Track Type */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_CD_STATUS_TRACK_TYPE; |
| msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) |
| { |
| SDL_free(mtr); |
| return (CD_ERROR); |
| } |
| if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK; |
| else cdrom->track[i].type = SDL_DATA_TRACK; |
| /* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */ |
| cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr); |
| /* Set Track Offset */ |
| cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr); |
| } |
| SDL_free(mtr); |
| return(0); |
| } |
| |
| |
| /* Get CD-ROM status - Ready for MCI */ |
| static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) |
| { |
| CDstatus status; |
| MCI_STATUS_PARMS msp; |
| |
| /* Get Status from MCI */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_STATUS_MODE; |
| msp.ulValue = (ULONG)NULL; /* No additional information */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; |
| else |
| { |
| switch(msp.ulReturn) |
| { |
| case MCI_MODE_NOT_READY: |
| status = CD_TRAYEMPTY; |
| break; |
| case MCI_MODE_PAUSE: |
| status = CD_PAUSED; |
| break; |
| case MCI_MODE_PLAY: |
| status = CD_PLAYING; |
| break; |
| case MCI_MODE_STOP: |
| status = CD_STOPPED; |
| break; |
| /* These cases should not occour */ |
| case MCI_MODE_RECORD: |
| case MCI_MODE_SEEK: |
| default: |
| status = CD_ERROR; |
| break; |
| } |
| } |
| |
| /* Determine position */ |
| if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */ |
| { |
| if ((status == CD_PLAYING) || (status == CD_PAUSED)) |
| { |
| /* Get Position */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_STATUS_POSITION; |
| msp.ulValue = (ULONG)NULL; /* No additiona info */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR); |
| /* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */ |
| *position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn)); |
| } |
| else *position = 0; |
| } |
| return(status); |
| } |
| |
| /* Start play - Ready for MCI */ |
| static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) |
| { |
| MCI_GENERIC_PARMS mgp; |
| MCI_STATUS_PARMS msp; |
| MCI_PLAY_PARMS mpp; |
| ULONG min,sec,frm; |
| |
| /* Start MSF */ |
| FRAMES_TO_MSF(start, &min, &sec, &frm); |
| MSF_MINUTE(mpp.ulFrom) = min; |
| MSF_SECOND(mpp.ulFrom) = sec; |
| MSF_FRAME(mpp.ulFrom) = frm; |
| /* End MSF */ |
| FRAMES_TO_MSF(start+length, &min, &sec, &frm); |
| MSF_MINUTE(mpp.ulTo) = min; |
| MSF_SECOND(mpp.ulTo) = sec; |
| MSF_FRAME(mpp.ulTo) = frm; |
| #ifdef DEBUG_CDROM |
| fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", |
| playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, |
| playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); |
| #endif |
| /* Verifies if it is paused first... and if it is, unpause before stopping it. */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_STATUS_MODE; |
| msp.ulValue = (ULONG)NULL; /* No additional information */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) |
| { |
| if (msp.ulReturn == MCI_MODE_PAUSE) |
| { |
| mgp.hwndCallback = (HWND)NULL; // None |
| mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); |
| } |
| } |
| /* Now play it. */ |
| mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; |
| return (CD_ERROR); |
| } |
| |
| /* Pause play - Ready for MCI */ |
| static int SDL_SYS_CDPause(SDL_CD *cdrom) |
| { |
| MCI_GENERIC_PARMS mgp; |
| |
| mgp.hwndCallback = (HWND)NULL; // None |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
| return(CD_ERROR); |
| } |
| |
| /* Resume play - Ready for MCI */ |
| static int SDL_SYS_CDResume(SDL_CD *cdrom) |
| { |
| MCI_GENERIC_PARMS mgp; |
| |
| mgp.hwndCallback = (HWND)NULL; // None |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
| return(CD_ERROR); |
| } |
| |
| /* Stop play - Ready for MCI */ |
| static int SDL_SYS_CDStop(SDL_CD *cdrom) |
| { |
| MCI_GENERIC_PARMS mgp; |
| MCI_STATUS_PARMS msp; |
| |
| /* Verifies if it is paused first... and if it is, unpause before stopping it. */ |
| msp.hwndCallback = (HWND)NULL; /* None */ |
| msp.ulReturn = (ULONG)NULL; /* We want this information */ |
| msp.ulItem = MCI_STATUS_MODE; |
| msp.ulValue = (ULONG)NULL; /* No additional information */ |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) |
| { |
| if (msp.ulReturn == MCI_MODE_PAUSE) |
| { |
| mgp.hwndCallback = (HWND)NULL; // None |
| mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); |
| } |
| } |
| /* Now stops the media */ |
| mgp.hwndCallback = (HWND)NULL; // None |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; |
| return(CD_ERROR); |
| } |
| |
| /* Eject the CD-ROM - Ready for MCI */ |
| static int SDL_SYS_CDEject(SDL_CD *cdrom) |
| { |
| MCI_SET_PARMS msp; |
| |
| msp.hwndCallback = (HWND)NULL; // None |
| msp.ulTimeFormat = (ULONG)NULL; // No change |
| msp.ulSpeedFormat = (ULONG)NULL; // No change |
| msp.ulAudio = (ULONG)NULL; // No Channel |
| msp.ulLevel = (ULONG)NULL; // No Volume |
| msp.ulOver = (ULONG)NULL; // No Delay |
| msp.ulItem = (ULONG)NULL; // No item |
| msp.ulValue = (ULONG)NULL; // No value for item flag |
| if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; |
| return(CD_ERROR); |
| } |
| |
| /* Close the CD-ROM handle - Ready for MCI */ |
| static void SDL_SYS_CDClose(SDL_CD *cdrom) |
| { |
| MCI_GENERIC_PARMS mgp; |
| |
| mgp.hwndCallback = (HWND)NULL; // None |
| mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); |
| } |
| |
| /* Finalize CDROM Subsystem - Ready for MCI */ |
| void SDL_SYS_CDQuit(void) |
| { |
| int i; |
| |
| if ( SDL_numcds > 0 ) |
| { |
| for ( i=0; i<SDL_numcds; ++i ) |
| { |
| SDL_free(SDL_cdlist[i]); |
| } |
| SDL_numcds = 0; |
| } |
| } |
| |
| #endif /* SDL_CDROM_OS2 */ |