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 (at) 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 */ 42 static char *SDL_cdlist[MAX_DRIVES]; 43 //static dev_t SDL_cdmode[MAX_DRIVES]; 44 45 /* The system-dependent CD control functions */ 46 static const char *SDL_SYS_CDName(int drive); 47 static int SDL_SYS_CDOpen(int drive); 48 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); 49 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); 50 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); 51 static int SDL_SYS_CDPause(SDL_CD *cdrom); 52 static int SDL_SYS_CDResume(SDL_CD *cdrom); 53 static int SDL_SYS_CDStop(SDL_CD *cdrom); 54 static int SDL_SYS_CDEject(SDL_CD *cdrom); 55 static 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 */ 63 int SDL_SYS_CDInit(void) 64 { 65 int i; /* generig counter */ 66 MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ 67 CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ 68 69 /* Fill in our driver capabilities */ 70 SDL_CDcaps.Name = SDL_SYS_CDName; 71 SDL_CDcaps.Open = SDL_SYS_CDOpen; 72 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; 73 SDL_CDcaps.Status = SDL_SYS_CDStatus; 74 SDL_CDcaps.Play = SDL_SYS_CDPlay; 75 SDL_CDcaps.Pause = SDL_SYS_CDPause; 76 SDL_CDcaps.Resume = SDL_SYS_CDResume; 77 SDL_CDcaps.Stop = SDL_SYS_CDStop; 78 SDL_CDcaps.Eject = SDL_SYS_CDEject; 79 SDL_CDcaps.Close = SDL_SYS_CDClose; 80 81 /* Get the number of CD ROMs in the System */ 82 /* Clean SysInfo structure */ 83 SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); 84 /* Prepare structure to Ask Numer of Audio CDs */ 85 msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ 86 msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ 87 msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ 88 if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 89 SDL_numcds = atoi(SysInfoRet); 90 if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ 91 92 /* Get and Add their system name to the SDL_cdlist */ 93 msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ 94 msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ 95 msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ 96 for (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 } 107 return(0); 108 } 109 110 /* Return CDAudio System Dependent Device Name - Ready for MCI*/ 111 static const char *SDL_SYS_CDName(int drive) 112 { 113 return(SDL_cdlist[drive]); 114 } 115 116 /* Open CDAudio Device - Ready for MCI */ 117 static int SDL_SYS_CDOpen(int drive) 118 { 119 MCI_OPEN_PARMS mop; 120 MCI_SET_PARMS msp; 121 MCI_GENERIC_PARMS mgp; 122 123 /* Open the device */ 124 mop.hwndCallback = (HWND)NULL; // None 125 mop.usDeviceID = (USHORT)NULL; // Will be returned. 126 mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device 127 if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 128 /* Set time format */ 129 msp.hwndCallback = (HWND)NULL; // None 130 msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure 131 msp.ulSpeedFormat = (ULONG)NULL; // No change 132 msp.ulAudio = (ULONG)NULL; // No Channel 133 msp.ulLevel = (ULONG)NULL; // No Volume 134 msp.ulOver = (ULONG)NULL; // No Delay 135 msp.ulItem = (ULONG)NULL; // No item 136 msp.ulValue = (ULONG)NULL; // No value for item flag 137 if (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 */ 139 mgp.hwndCallback = (HWND)NULL; // None 140 mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0); 141 return(CD_ERROR); 142 } 143 144 /* Get CD Table Of Contents - Ready for MCI */ 145 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) 146 { 147 MCI_TOC_PARMS mtp; 148 MCI_STATUS_PARMS msp; 149 MCI_TOC_REC * mtr; 150 INT i; 151 152 /* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */ 153 if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; 154 155 /* Get Number of Tracks */ 156 msp.hwndCallback = (HWND)NULL; /* None */ 157 msp.ulReturn = (ULONG)NULL; /* We want this information */ 158 msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; 159 msp.ulValue = (ULONG)NULL; /* No additional information */ 160 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); 161 cdrom->numtracks = msp.ulReturn; 162 if ( cdrom->numtracks > SDL_MAX_TRACKS ) 163 { 164 cdrom->numtracks = SDL_MAX_TRACKS; 165 } 166 /* Alocate space for TOC data */ 167 mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); 168 if ( mtr == NULL ) 169 { 170 SDL_OutOfMemory(); 171 return(-1); 172 } 173 /* Get TOC from CD */ 174 mtp.pBuf = mtr; 175 mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); 176 if (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 */ 183 for (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 } 204 SDL_free(mtr); 205 return(0); 206 } 207 208 209 /* Get CD-ROM status - Ready for MCI */ 210 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) 211 { 212 CDstatus status; 213 MCI_STATUS_PARMS msp; 214 215 /* Get Status from MCI */ 216 msp.hwndCallback = (HWND)NULL; /* None */ 217 msp.ulReturn = (ULONG)NULL; /* We want this information */ 218 msp.ulItem = MCI_STATUS_MODE; 219 msp.ulValue = (ULONG)NULL; /* No additional information */ 220 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; 221 else 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 */ 247 if (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 } 262 return(status); 263 } 264 265 /* Start play - Ready for MCI */ 266 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) 267 { 268 MCI_GENERIC_PARMS mgp; 269 MCI_STATUS_PARMS msp; 270 MCI_PLAY_PARMS mpp; 271 ULONG min,sec,frm; 272 273 /* Start MSF */ 274 FRAMES_TO_MSF(start, &min, &sec, &frm); 275 MSF_MINUTE(mpp.ulFrom) = min; 276 MSF_SECOND(mpp.ulFrom) = sec; 277 MSF_FRAME(mpp.ulFrom) = frm; 278 /* End MSF */ 279 FRAMES_TO_MSF(start+length, &min, &sec, &frm); 280 MSF_MINUTE(mpp.ulTo) = min; 281 MSF_SECOND(mpp.ulTo) = sec; 282 MSF_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. */ 289 msp.hwndCallback = (HWND)NULL; /* None */ 290 msp.ulReturn = (ULONG)NULL; /* We want this information */ 291 msp.ulItem = MCI_STATUS_MODE; 292 msp.ulValue = (ULONG)NULL; /* No additional information */ 293 if (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. */ 302 mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp 303 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; 304 return (CD_ERROR); 305 } 306 307 /* Pause play - Ready for MCI */ 308 static int SDL_SYS_CDPause(SDL_CD *cdrom) 309 { 310 MCI_GENERIC_PARMS mgp; 311 312 mgp.hwndCallback = (HWND)NULL; // None 313 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 314 return(CD_ERROR); 315 } 316 317 /* Resume play - Ready for MCI */ 318 static int SDL_SYS_CDResume(SDL_CD *cdrom) 319 { 320 MCI_GENERIC_PARMS mgp; 321 322 mgp.hwndCallback = (HWND)NULL; // None 323 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 324 return(CD_ERROR); 325 } 326 327 /* Stop play - Ready for MCI */ 328 static int SDL_SYS_CDStop(SDL_CD *cdrom) 329 { 330 MCI_GENERIC_PARMS mgp; 331 MCI_STATUS_PARMS msp; 332 333 /* Verifies if it is paused first... and if it is, unpause before stopping it. */ 334 msp.hwndCallback = (HWND)NULL; /* None */ 335 msp.ulReturn = (ULONG)NULL; /* We want this information */ 336 msp.ulItem = MCI_STATUS_MODE; 337 msp.ulValue = (ULONG)NULL; /* No additional information */ 338 if (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 */ 347 mgp.hwndCallback = (HWND)NULL; // None 348 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; 349 return(CD_ERROR); 350 } 351 352 /* Eject the CD-ROM - Ready for MCI */ 353 static int SDL_SYS_CDEject(SDL_CD *cdrom) 354 { 355 MCI_SET_PARMS msp; 356 357 msp.hwndCallback = (HWND)NULL; // None 358 msp.ulTimeFormat = (ULONG)NULL; // No change 359 msp.ulSpeedFormat = (ULONG)NULL; // No change 360 msp.ulAudio = (ULONG)NULL; // No Channel 361 msp.ulLevel = (ULONG)NULL; // No Volume 362 msp.ulOver = (ULONG)NULL; // No Delay 363 msp.ulItem = (ULONG)NULL; // No item 364 msp.ulValue = (ULONG)NULL; // No value for item flag 365 if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; 366 return(CD_ERROR); 367 } 368 369 /* Close the CD-ROM handle - Ready for MCI */ 370 static void SDL_SYS_CDClose(SDL_CD *cdrom) 371 { 372 MCI_GENERIC_PARMS mgp; 373 374 mgp.hwndCallback = (HWND)NULL; // None 375 mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); 376 } 377 378 /* Finalize CDROM Subsystem - Ready for MCI */ 379 void SDL_SYS_CDQuit(void) 380 { 381 int i; 382 383 if ( 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