1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken@libsdl.org 21*/ 22#include "SDL_config.h" 23 24#ifdef SDL_CDROM_OS2 25 26/* Functions for system-level CD-ROM audio control */ 27 28#define INCL_MCIOS2 29#include <os2.h> 30#include <os2me.h> 31 32#include "SDL_cdrom.h" 33#include "../SDL_syscdrom.h" 34 35/* Size of MCI result buffer (in bytes) */ 36#define MCI_CMDRETBUFSIZE 128 37 38/* The maximum number of CD-ROM drives we'll detect */ 39#define MAX_DRIVES 16 40 41/* A list of available CD-ROM drives */ 42static char *SDL_cdlist[MAX_DRIVES]; 43//static dev_t SDL_cdmode[MAX_DRIVES]; 44 45/* The system-dependent CD control functions */ 46static const char *SDL_SYS_CDName(int drive); 47static int SDL_SYS_CDOpen(int drive); 48static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); 49static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); 50static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); 51static int SDL_SYS_CDPause(SDL_CD *cdrom); 52static int SDL_SYS_CDResume(SDL_CD *cdrom); 53static int SDL_SYS_CDStop(SDL_CD *cdrom); 54static int SDL_SYS_CDEject(SDL_CD *cdrom); 55static void SDL_SYS_CDClose(SDL_CD *cdrom); 56 57/* MCI Timing Functions */ 58#define MCI_MMTIMEPERSECOND 3000 59#define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND) 60 61 62/* Ready for MCI CDAudio Devices */ 63int SDL_SYS_CDInit(void) 64{ 65int i; /* generig counter */ 66MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ 67CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ 68 69/* Fill in our driver capabilities */ 70SDL_CDcaps.Name = SDL_SYS_CDName; 71SDL_CDcaps.Open = SDL_SYS_CDOpen; 72SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; 73SDL_CDcaps.Status = SDL_SYS_CDStatus; 74SDL_CDcaps.Play = SDL_SYS_CDPlay; 75SDL_CDcaps.Pause = SDL_SYS_CDPause; 76SDL_CDcaps.Resume = SDL_SYS_CDResume; 77SDL_CDcaps.Stop = SDL_SYS_CDStop; 78SDL_CDcaps.Eject = SDL_SYS_CDEject; 79SDL_CDcaps.Close = SDL_SYS_CDClose; 80 81/* Get the number of CD ROMs in the System */ 82/* Clean SysInfo structure */ 83SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); 84/* Prepare structure to Ask Numer of Audio CDs */ 85msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ 86msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ 87msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ 88if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 89SDL_numcds = atoi(SysInfoRet); 90if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ 91 92/* Get and Add their system name to the SDL_cdlist */ 93msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ 94msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ 95msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ 96for (i=0; i<SDL_numcds; i++) 97 { 98 msp.ulNumber = i+1; 99 mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0); 100 SDL_cdlist[i] = SDL_strdup(SysInfoRet); 101 if ( SDL_cdlist[i] == NULL ) 102 { 103 SDL_OutOfMemory(); 104 return(-1); 105 } 106 } 107return(0); 108} 109 110/* Return CDAudio System Dependent Device Name - Ready for MCI*/ 111static const char *SDL_SYS_CDName(int drive) 112{ 113return(SDL_cdlist[drive]); 114} 115 116/* Open CDAudio Device - Ready for MCI */ 117static int SDL_SYS_CDOpen(int drive) 118{ 119MCI_OPEN_PARMS mop; 120MCI_SET_PARMS msp; 121MCI_GENERIC_PARMS mgp; 122 123/* Open the device */ 124mop.hwndCallback = (HWND)NULL; // None 125mop.usDeviceID = (USHORT)NULL; // Will be returned. 126mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device 127if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 128/* Set time format */ 129msp.hwndCallback = (HWND)NULL; // None 130msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure 131msp.ulSpeedFormat = (ULONG)NULL; // No change 132msp.ulAudio = (ULONG)NULL; // No Channel 133msp.ulLevel = (ULONG)NULL; // No Volume 134msp.ulOver = (ULONG)NULL; // No Delay 135msp.ulItem = (ULONG)NULL; // No item 136msp.ulValue = (ULONG)NULL; // No value for item flag 137if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID); 138/* Error setting time format? - Close opened device */ 139mgp.hwndCallback = (HWND)NULL; // None 140mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0); 141return(CD_ERROR); 142} 143 144/* Get CD Table Of Contents - Ready for MCI */ 145static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) 146{ 147MCI_TOC_PARMS mtp; 148MCI_STATUS_PARMS msp; 149MCI_TOC_REC * mtr; 150INT i; 151 152/* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */ 153if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; 154 155/* Get Number of Tracks */ 156msp.hwndCallback = (HWND)NULL; /* None */ 157msp.ulReturn = (ULONG)NULL; /* We want this information */ 158msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; 159msp.ulValue = (ULONG)NULL; /* No additional information */ 160if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 161cdrom->numtracks = msp.ulReturn; 162if ( cdrom->numtracks > SDL_MAX_TRACKS ) 163 { 164 cdrom->numtracks = SDL_MAX_TRACKS; 165 } 166/* Alocate space for TOC data */ 167mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); 168if ( mtr == NULL ) 169 { 170 SDL_OutOfMemory(); 171 return(-1); 172 } 173/* Get TOC from CD */ 174mtp.pBuf = mtr; 175mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); 176if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS) 177 { 178 SDL_OutOfMemory(); 179 SDL_free(mtr); 180 return(CD_ERROR); 181 } 182/* Fill SDL Tracks Structure */ 183for (i=0; i<cdrom->numtracks; i++) 184 { 185 /* Set Track ID */ 186 cdrom->track[i].id = (mtr+i)->TrackNum; 187 /* Set Track Type */ 188 msp.hwndCallback = (HWND)NULL; /* None */ 189 msp.ulReturn = (ULONG)NULL; /* We want this information */ 190 msp.ulItem = MCI_CD_STATUS_TRACK_TYPE; 191 msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */ 192 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) 193 { 194 SDL_free(mtr); 195 return (CD_ERROR); 196 } 197 if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK; 198 else cdrom->track[i].type = SDL_DATA_TRACK; 199 /* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */ 200 cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr); 201 /* Set Track Offset */ 202 cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr); 203 } 204SDL_free(mtr); 205return(0); 206} 207 208 209/* Get CD-ROM status - Ready for MCI */ 210static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) 211{ 212CDstatus status; 213MCI_STATUS_PARMS msp; 214 215/* Get Status from MCI */ 216msp.hwndCallback = (HWND)NULL; /* None */ 217msp.ulReturn = (ULONG)NULL; /* We want this information */ 218msp.ulItem = MCI_STATUS_MODE; 219msp.ulValue = (ULONG)NULL; /* No additional information */ 220if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; 221else 222 { 223 switch(msp.ulReturn) 224 { 225 case MCI_MODE_NOT_READY: 226 status = CD_TRAYEMPTY; 227 break; 228 case MCI_MODE_PAUSE: 229 status = CD_PAUSED; 230 break; 231 case MCI_MODE_PLAY: 232 status = CD_PLAYING; 233 break; 234 case MCI_MODE_STOP: 235 status = CD_STOPPED; 236 break; 237 /* These cases should not occour */ 238 case MCI_MODE_RECORD: 239 case MCI_MODE_SEEK: 240 default: 241 status = CD_ERROR; 242 break; 243 } 244 } 245 246/* Determine position */ 247if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */ 248 { 249 if ((status == CD_PLAYING) || (status == CD_PAUSED)) 250 { 251 /* Get Position */ 252 msp.hwndCallback = (HWND)NULL; /* None */ 253 msp.ulReturn = (ULONG)NULL; /* We want this information */ 254 msp.ulItem = MCI_STATUS_POSITION; 255 msp.ulValue = (ULONG)NULL; /* No additiona info */ 256 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR); 257 /* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */ 258 *position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn)); 259 } 260 else *position = 0; 261 } 262return(status); 263} 264 265/* Start play - Ready for MCI */ 266static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) 267{ 268MCI_GENERIC_PARMS mgp; 269MCI_STATUS_PARMS msp; 270MCI_PLAY_PARMS mpp; 271ULONG min,sec,frm; 272 273/* Start MSF */ 274FRAMES_TO_MSF(start, &min, &sec, &frm); 275MSF_MINUTE(mpp.ulFrom) = min; 276MSF_SECOND(mpp.ulFrom) = sec; 277MSF_FRAME(mpp.ulFrom) = frm; 278/* End MSF */ 279FRAMES_TO_MSF(start+length, &min, &sec, &frm); 280MSF_MINUTE(mpp.ulTo) = min; 281MSF_SECOND(mpp.ulTo) = sec; 282MSF_FRAME(mpp.ulTo) = frm; 283#ifdef DEBUG_CDROM 284 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", 285 playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, 286 playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); 287#endif 288/* Verifies if it is paused first... and if it is, unpause before stopping it. */ 289msp.hwndCallback = (HWND)NULL; /* None */ 290msp.ulReturn = (ULONG)NULL; /* We want this information */ 291msp.ulItem = MCI_STATUS_MODE; 292msp.ulValue = (ULONG)NULL; /* No additional information */ 293if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) 294 { 295 if (msp.ulReturn == MCI_MODE_PAUSE) 296 { 297 mgp.hwndCallback = (HWND)NULL; // None 298 mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); 299 } 300 } 301/* Now play it. */ 302mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp 303if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; 304return (CD_ERROR); 305} 306 307/* Pause play - Ready for MCI */ 308static int SDL_SYS_CDPause(SDL_CD *cdrom) 309{ 310MCI_GENERIC_PARMS mgp; 311 312mgp.hwndCallback = (HWND)NULL; // None 313if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 314return(CD_ERROR); 315} 316 317/* Resume play - Ready for MCI */ 318static int SDL_SYS_CDResume(SDL_CD *cdrom) 319{ 320MCI_GENERIC_PARMS mgp; 321 322mgp.hwndCallback = (HWND)NULL; // None 323if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 324return(CD_ERROR); 325} 326 327/* Stop play - Ready for MCI */ 328static int SDL_SYS_CDStop(SDL_CD *cdrom) 329{ 330MCI_GENERIC_PARMS mgp; 331MCI_STATUS_PARMS msp; 332 333/* Verifies if it is paused first... and if it is, unpause before stopping it. */ 334msp.hwndCallback = (HWND)NULL; /* None */ 335msp.ulReturn = (ULONG)NULL; /* We want this information */ 336msp.ulItem = MCI_STATUS_MODE; 337msp.ulValue = (ULONG)NULL; /* No additional information */ 338if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) 339 { 340 if (msp.ulReturn == MCI_MODE_PAUSE) 341 { 342 mgp.hwndCallback = (HWND)NULL; // None 343 mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); 344 } 345 } 346/* Now stops the media */ 347mgp.hwndCallback = (HWND)NULL; // None 348if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 349return(CD_ERROR); 350} 351 352/* Eject the CD-ROM - Ready for MCI */ 353static int SDL_SYS_CDEject(SDL_CD *cdrom) 354{ 355MCI_SET_PARMS msp; 356 357msp.hwndCallback = (HWND)NULL; // None 358msp.ulTimeFormat = (ULONG)NULL; // No change 359msp.ulSpeedFormat = (ULONG)NULL; // No change 360msp.ulAudio = (ULONG)NULL; // No Channel 361msp.ulLevel = (ULONG)NULL; // No Volume 362msp.ulOver = (ULONG)NULL; // No Delay 363msp.ulItem = (ULONG)NULL; // No item 364msp.ulValue = (ULONG)NULL; // No value for item flag 365if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; 366return(CD_ERROR); 367} 368 369/* Close the CD-ROM handle - Ready for MCI */ 370static void SDL_SYS_CDClose(SDL_CD *cdrom) 371{ 372MCI_GENERIC_PARMS mgp; 373 374mgp.hwndCallback = (HWND)NULL; // None 375mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); 376} 377 378/* Finalize CDROM Subsystem - Ready for MCI */ 379void SDL_SYS_CDQuit(void) 380{ 381int i; 382 383if ( SDL_numcds > 0 ) 384 { 385 for ( i=0; i<SDL_numcds; ++i ) 386 { 387 SDL_free(SDL_cdlist[i]); 388 } 389 SDL_numcds = 0; 390 } 391} 392 393#endif /* SDL_CDROM_OS2 */ 394